How to add security headers in Next.js (including CSP)

Next.js doesn't send security headers by default — you add them. It's a small change, with one genuinely tricky part: a Content-Security-Policy strict enough to help without blocking your own app. Here's the shape of it, and the trap to avoid.
The straightforward headers
Most security headers are static strings that should ride on every response: Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy. Next.js has a headers configuration that applies them across all routes — set them once there and you're done with this half.
If you're unsure what each of these does before you set it, that's the what are security headers rundown.
The hard part: CSP with a nonce
Content-Security-Policy is where people get stuck, because the easy version undermines the whole point. Adding 'unsafe-inline' to make your inline scripts work re-opens the exact hole CSP exists to close.
The correct approach for an app with inline scripts is a nonce: generate a random token per request in middleware, attach it to your CSP header and to each inline script, and the browser runs only the scripts carrying that request's token. It's more moving parts, but it's the difference between a CSP that protects you and one that's decorative.
report-only mode first. It reports what would be blocked without actually blocking anything, so you can find every script and style your own app depends on before you enforce — instead of shipping a policy that white-screens your homepage.Generate it for your version
Because the right API depends on your Next.js version, the safest path is to have the model check your version and generate the version-correct setup, nonce and all:
Add security headers to my Next.js app. Check my Next.js version first and use the approach that's correct for it — don't guess from old tutorials. Requirements: 1. Set these globally so every response carries them: Strict-Transport-Security (HSTS), X-Frame-Options (or CSP frame-ancestors), X-Content-Type-Options: nosniff, Referrer-Policy, and a Permissions-Policy. 2. Add a Content-Security-Policy. If my app uses inline scripts, use a nonce-based CSP generated per-request (via middleware) rather than 'unsafe-inline', and show me how to thread the nonce through. 3. Tell me the right place for these in MY version of Next.js (e.g. the headers() config, middleware, or wherever the current docs say), and flag anything that differs from older App Router / Pages Router advice. 4. Warn me about the common breakage: a too-strict CSP that blocks my own scripts/styles, and how to test in report-only mode first. Show me the full config/middleware and tell me how to verify the headers are actually being sent.
Next.js's own CSP guide is the reference to check against your version.
Verify they're actually sent
Configuring headers and sending headers aren't the same thing — a redirect, a CDN, or a misplaced config can strip them. Confirm on the live URL that they arrive:
free tool · no loginSecurity headers checkScan your deployed Next.js app and confirm the headers you configured are actually being sent to browsers. No login.Ship the headers — then watch the deployed app.
The scanner confirms your headers went live. Tell Me When Down watches the app after — SSL that lapses, a route that starts erroring, a site that goes down — free, no card, so a bad deploy doesn't slip past you.
spot something wrong or out of date? [email protected] — we'll fix it