Step-by-Step Guide
5 steps

How to Add Security Headers in Next.js

Next.js does not add security headers by default. Without them, your app is vulnerable to XSS, clickjacking, MIME sniffing, and other browser-based attacks. This guide shows you how to add comprehensive security headers using next.config.js and middleware.

Find security issues automatically before attackers do.

Follow These Steps

1

Add basic security headers in next.config.js

Configure headers that apply to all routes.

Code Example
// next.config.js
const securityHeaders = [
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  { key: 'X-Frame-Options', value: 'DENY' },
  { key: 'X-XSS-Protection', value: '0' },
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
  { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
  { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' }
]

module.exports = {
  async headers() {
    return [{ source: '/(.*)', headers: securityHeaders }]
  }
}

X-XSS-Protection is set to 0 because modern browsers have deprecated it. CSP is the proper replacement.

2

Add Content Security Policy with nonce-based script loading

Use middleware to generate a unique nonce for each request, allowing inline scripts while blocking XSS.

Code Example
// middleware.ts
import { NextResponse } from 'next/server'

export function middleware(request: Request) {
  const nonce = Buffer.from(crypto.randomUUID()).toString('base64')
  const cspHeader = [
    `default-src 'self'`,
    `script-src 'self' 'nonce-${nonce}' 'strict-dynamic'`,
    `style-src 'self' 'unsafe-inline'`,
    `img-src 'self' blob: data:`,
    `font-src 'self'`,
    `connect-src 'self'`,
    `frame-ancestors 'none'`,
    `base-uri 'self'`,
    `form-action 'self'`
  ].join('; ')

  const requestHeaders = new Headers(request.headers)
  requestHeaders.set('x-nonce', nonce)

  const response = NextResponse.next({ request: { headers: requestHeaders } })
  response.headers.set('Content-Security-Policy', cspHeader)
  return response
}
3

Pass the nonce to Script components

Use the nonce from the middleware in your Script tags.

Code Example
// app/layout.tsx
import { headers } from 'next/headers'
import Script from 'next/script'

export default async function RootLayout({ children }: { children: React.ReactNode }) {
  const headersList = await headers()
  const nonce = headersList.get('x-nonce') || ''
  
  return (
    <html lang="en">
      <body>
        {children}
        <Script nonce={nonce} src="/analytics.js" />
      </body>
    </html>
  )
}
4

Configure Permissions-Policy based on your app needs

Adjust the Permissions-Policy header to match what browser APIs your app actually uses.

Code Example
// If your app uses geolocation:
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=(self)' }

// If your app uses camera (video chat):
{ key: 'Permissions-Policy', value: 'camera=(self), microphone=(self), geolocation=()' }

// If your app uses none of these (most common):
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' }

Check if your app uses geolocation, camera, or microphone before setting Permissions-Policy. Blocking APIs your app needs will break functionality.

5

Verify headers are applied

Check that headers are present on your deployed site.

Code Example
# Check headers with curl
curl -I https://yourdomain.com

# Or use browser DevTools > Network tab > click any request > Headers

Run a VAS scan to automatically verify all security headers are configured correctly.

What You'll Achieve

Your Next.js app has comprehensive security headers including X-Content-Type-Options, X-Frame-Options, HSTS, Referrer-Policy, Permissions-Policy, and a nonce-based Content Security Policy.

Common Mistakes to Avoid

Mistake

Using unsafe-inline for script-src in CSP

Fix

Use nonce-based CSP instead. Generate a unique nonce per request in middleware and pass it to Script components.

Mistake

Setting Permissions-Policy that blocks APIs your app uses

Fix

Check if your app uses geolocation, camera, or microphone before blocking them. Use (self) instead of () for APIs your app needs.

Mistake

Only adding headers in development, not production

Fix

next.config.js headers apply to all environments. Verify with curl or DevTools after deploying to production.

Frequently Asked Questions

Do I need both next.config.js headers and middleware?

Use next.config.js for static headers (HSTS, X-Frame-Options). Use middleware for dynamic headers like CSP with per-request nonces. They work together.

Will security headers break my Next.js app?

Most headers are safe to add. CSP is the most likely to cause issues if configured too restrictively. Start with report-only mode and monitor for violations before enforcing.

Does Vercel add security headers automatically?

No. Vercel provides HTTPS but does not add application security headers. You must configure them in your Next.js application.

Ready to Secure Your App?

VAS automatically scans your deployed app for the security issues covered in this guide. Get actionable results in minutes.

Start Security Scan