Next.js Security Headers · A Working Config
Next.js doesn't ship security headers by default. You add them via the `headers()` async function in `next.config.js`. The five headers that matter: Content-Security-Policy, Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, and Referrer-Policy. Together they close XSS, clickjacking, MIME-sniffing, and mixed-content classes of bugs.
Common misconfigurations
- No CSP at all · The single highest-leverage header. Without it, any injected script runs freely.
- `X-Frame-Options` missing · Your site can be embedded in an iframe on an attacker page and clickjacked. Set to `DENY` unless you specifically need embedding.
- HSTS without `includeSubDomains` · Attackers downgrade `something.yoursite.com` to HTTP. Include subdomains from day one.
- CSP with `unsafe-inline` in production · Nullifies most of CSP's protection. Use nonces or hashes for inline scripts that truly need to run.
Example
next.config.js · sensible defaults
module.exports = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{ key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains; preload' },
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
{ key: 'Content-Security-Policy', value: "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://*.supabase.co;" },
],
},
];
},
};
Frequently asked
Do I need CSP if I use React?
Yes · React protects against reflected XSS by escaping, but a CSP is the belt to that suspenders. Third-party scripts and `dangerouslySetInnerHTML` bypass React's protection.
How do I test my headers?
Use securityheaders.com or run SimplyScan · both grade your live URL against the standard set.
Why not use Vercel's `vercel.json`?
Both work. `next.config.js` keeps headers with the app; `vercel.json` couples them to the host. Pick one.
Scan your app →