Guide · Open source
How to use Helmet: set secure Express HTTP headers
Updated · written with AI from the project's own documentation and checked against our catalogue data
Helmet is a middleware package for Node.js and Express apps that sets HTTP response headers, such as Content-Security-Policy and Strict-Transport-Security, which tell browsers how to handle your site more safely. This guide shows how to add it to an Express app, turn individual headers on or off, and tune the Content-Security-Policy for your own scripts. By the end you will have a working baseline and know where Helmet stops.
Quick start
- 1Install the package. Add Helmet to your Node.js project using your package manager.
- 2Import Helmet. Import helmet at the top of your Express app file.
- 3Register the middleware. Call app.use(helmet()) before your routes so headers apply to all responses.
- 4Disable headers you do not need. Pass false for any header option you want turned off, such as contentSecurityPolicy.
- 5Configure the Content-Security-Policy. Pass a directives object to tune script-src, style-src and other directives for your scripts.
- 6Test your policy. Run your pages and check the policy with a CSP checker, since Helmet validates the CSP very little.
What Helmet needs before you start
Helmet is built for Node.js and Express. The README is written around Express, so if your project uses a different framework or does not control its own response headers, this middleware may not apply.
You also need to be able to change how your app sends responses. Helmet works by setting headers on the response, so it has no effect on files served by a host that sets its own headers.
- Node.js
- Express
- Access to the Express app code where middleware is registered
Install Helmet and add it to your app
Helmet is installed through a package manager. The README's quick start imports it and registers it with app.use. Calling helmet() with no options sets 13 HTTP response headers in your app.
Register Helmet before your routes so the headers are added to every response.
import helmet from "helmet";
const app = express();
app.use(helmet());Disable headers you do not want
Each header can be disabled by passing false for its option name. The example below turns off Content-Security-Policy and X-Download-Options while keeping the rest of the defaults.
- Pass false for a header option to turn that header off.
- Other headers keep their default behaviour unless you disable them too.
// Disable the Content-Security-Policy and X-Download-Options headers
app.use(
helmet({
contentSecurityPolicy: false,
xDownloadOptions: false,
}),
);Configure the Content-Security-Policy
The Content-Security-Policy header mitigates many attacks, such as cross-site scripting. The README says it is powerful but likely needs configuration for your specific app. Pass a nested directives object; keys can be camel case (defaultSrc) or kebab case (default-src).
Directives are merged into a default policy by default. Set useDefaults to false if you want to replace the defaults completely. You can also use a function in a directive value, which is called with the request and response objects, for example to add a per-request nonce.
Helmet performs very little validation on your CSP, so check your policy with a CSP checker such as CSP Evaluator.
- Override one directive: set script-src to 'self' and example.com.
- Set a directive to null to disable a default, such as style-src.
- Use reportOnly: true to send Content-Security-Policy-Report-Only instead.
app.use(
helmet({
contentSecurityPolicy: {
directives: {
"script-src": ["'self'", "example.com"],
},
},
}),
);Handle upgrade-insecure-requests in development
The upgrade-insecure-requests directive is set by default and causes browsers to upgrade HTTP to HTTPS. The README notes you may not be developing with HTTPS, and Safari will upgrade http://localhost to https://localhost, which can cause problems. You can disable the directive only in development.
const isDevelopment = app.get("env") === "development";
app.use(
helmet({
contentSecurityPolicy: {
directives: {
// Disable upgrade-insecure-requests in development.
"upgrade-insecure-requests": isDevelopment ? null : [],
},
},
}),
);Turn on optional headers such as Cross-Origin-Embedder-Policy
Some headers are not set by default. The README says Cross-Origin-Embedder-Policy is not set by default and can be enabled with true, which sets require-corp, or with a policy value such as credentialless. Cross-Origin-Opener-Policy and Cross-Origin-Resource-Policy are set to same-origin by default and can be changed the same way.
- Cross-Origin-Embedder-Policy: off by default; true gives require-corp.
- Cross-Origin-Opener-Policy: same-origin by default; same-origin-allow-popups is an option.
- Cross-Origin-Resource-Policy: same-origin by default; same-site is an option.
app.use(helmet({ crossOriginEmbedderPolicy: true }));What people use it for
- Adding a baseline of browser-side protection to a new Express web app without writing headers by hand.
- Allowing a specific external domain for scripts with a custom script-src directive.
- Using per-request nonces in the Content-Security-Policy with a function-based directive.
- Turning off upgrade-insecure-requests during local development to avoid Safari localhost problems.
Frequently asked questions
Is Helmet free to use?
Helmet is released under the MIT licence, according to the project's listing. Check the LICENSE file in the repository for the full terms before you rely on it.
Does Helmet work with frameworks other than Express?
The README is written around Express and describes Helmet as middleware for Node/Express apps. If you use a different framework, check its documentation before assuming Helmet fits.
What does helmet() actually set?
Calling helmet() with no options sets 13 HTTP response headers, including Content-Security-Policy and Strict-Transport-Security. Each one can be turned off individually.
How do I turn off one Helmet header?
Pass false for that header's option, for example contentSecurityPolicy: false. Other default headers stay on.
Why does my site break after adding Helmet?
The most likely cause is the Content-Security-Policy blocking a script or style source. Add the source to the matching directive, or use reportOnly to test first. In development, the upgrade-insecure-requests directive can break http://localhost in Safari.
Can Helmet replace input validation or a security review?
No. The project says Helmet is not a replacement for server-side input validation or a full security review, and it does very little validation of your CSP.
New agent skills, repos and AI tools — every week
The best new skills and open-source projects, the fastest-growing repos, and one free prompt. Five minutes to read. Unsubscribe anytime.
Our verdict
Helmet suits Express developers who want sensible security headers by default and a low-maintenance way to add them. It is less suitable if you use a non-Express framework, do not control response headers, or expect it to handle input validation or a full security review. Projects with complex scripts will need to spend time tuning the Content-Security-Policy.
Install options & downloads