How to add Strict-Transport-Security on Express / Node
Last updated · Reviewed by a CISSP-certified security practitioner
To add Strict-Transport-Security on Express / Node, set the header in app.js (helmet) with the value max-age=63072000; includeSubDomains; preload. Forces browsers to only use HTTPS for your domain. Restart the Node process and curl -I your app. Then confirm it with curl -I or a free FixSecurityHeaders scan.
What does Strict-Transport-Security do?
HSTS tells the browser to always connect over HTTPS for a set time, even if someone types http:// or clicks an old link.
Risk if missing: Without it, the first request can be downgraded to plain HTTP, letting attackers on public Wi‑Fi intercept or rewrite traffic (SSL stripping).
What is the Express / Node configuration?
Add this to app.js (helmet):
// npm i helmet
const helmet = require("helmet");
app.disable("x-powered-by");
app.use(helmet()); // sensible defaults
// Exact values recommended by FixSecurityHeaders:
app.use((req, res, next) => {
res.setHeader("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload");
next();
});How do I add it step by step?
- Open app.js (helmet).
- Paste the Strict-Transport-Security configuration shown below.
- Restart the Node process and curl -I your app.
- Run curl -I https://yourdomain.com and look for the strict-transport-security line.
- Scan your site on FixSecurityHeaders to confirm the grade improved.
How do I verify it worked?
curl -sI https://yourdomain.com | grep -i "strict-transport-security"
# expected:
# strict-transport-security: max-age=63072000; includeSubDomains; preloadCheck your site now
Free scan, instant grade, exact fixes for your stack.
What are the common mistakes?
- The preload directive is hard to undo: removal from browser preload lists takes months.
- includeSubDomains breaks any subdomain that still serves plain HTTP. Audit subdomains first.
- Start with a short max-age (e.g. 300) and ramp up to 1–2 years once verified.
- Browsers ignore HSTS sent over plain HTTP; it must be sent on the HTTPS response.
- Install with npm i helmet.
- Call app.use(helmet(...)) before your routes.
Quick reference
| Header | Strict-Transport-Security |
|---|---|
| Recommended value | max-age=63072000; includeSubDomains; preload |
| Stack | Express / Node |
| Where | app.js (helmet) |
| Compliance | PCI DSS 4.0 4.2.1, NIST 800-171 3.13.8, CMMC SC.L2-3.13.8, OWASP ASVS V14.4.5, SOC 2 CC6.7 |
FAQ
What value should I use for Strict-Transport-Security?
A safe default is max-age=63072000; includeSubDomains; preload. The preload directive is hard to undo: removal from browser preload lists takes months.
Why isn't Strict-Transport-Security showing up on Express / Node?
Install with npm i helmet. Also clear any CDN or page cache, and check you edited the config that actually serves your domain.
Does Strict-Transport-Security affect SEO or performance?
No measurable performance cost — it's a few bytes per response. It doesn't affect rankings directly, but a misconfigured policy can break page resources, so test before enforcing.
Which compliance frameworks reference Strict-Transport-Security?
PCI DSS 4.0 4.2.1, NIST 800-171 3.13.8, CMMC SC.L2-3.13.8, OWASP ASVS V14.4.5, SOC 2 CC6.7.
Related guides
- Strict-Transport-Security explained
- Strict-Transport-Security on Nginx
- Strict-Transport-Security on Apache
- Strict-Transport-Security on IIS
- Strict-Transport-Security on Cloudflare
- Content-Security-Policy on Express / Node
- X-Content-Type-Options on Express / Node
- X-Frame-Options on Express / Node
- Referrer-Policy on Express / Node