CSP Headers for Next.js Applications

Implement Content Security Policy in Next.js using middleware, next.config.js headers, and nonce injection. Handle App Router, Server Components, and Edge Runtime CSP requirements.

Framework-Specific

Detailed Explanation

CSP in Next.js

Next.js applications require careful CSP configuration because they combine server-rendered HTML, client-side hydration, and various data-fetching patterns. Next.js provides multiple ways to set CSP headers.

Method 1: Middleware (Recommended)

Middleware allows per-request nonce generation, which is the most secure approach:

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
  const csp = `
    default-src 'self';
    script-src 'self' 'nonce-${nonce}' 'strict-dynamic';
    style-src 'self' 'nonce-${nonce}';
    img-src 'self' data: blob:;
    font-src 'self';
    connect-src 'self';
    frame-ancestors 'none';
  `.replace(/\n/g, '');

  const response = NextResponse.next();
  response.headers.set('Content-Security-Policy', csp);
  response.headers.set('x-nonce', nonce);
  return response;
}

Method 2: next.config.js Headers

For static policies without nonces:

// next.config.js
module.exports = {
  async headers() {
    return [{
      source: '/(.*)',
      headers: [{
        key: 'Content-Security-Policy',
        value: "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
      }]
    }];
  }
};

Accessing the Nonce in Components

In Next.js App Router, pass the nonce through a Server Component:

// app/layout.tsx
import { headers } from 'next/headers';

export default async function RootLayout({ children }) {
  const headersList = await headers();
  const nonce = headersList.get('x-nonce') ?? '';

  return (
    <html>
      <body>
        <script nonce={nonce} />
        {children}
      </body>
    </html>
  );
}

Next.js-Specific Challenges

Inline scripts: Next.js injects inline scripts for page data (__NEXT_DATA__) and hydration. These need the nonce attribute, which Next.js 13.4+ supports natively via the nonce prop on <Script>.

next/script component:

import Script from 'next/script';
<Script src="https://analytics.example.com/script.js" nonce={nonce} strategy="afterInteractive" />

Image optimization: If using next/image with external sources, add those domains to img-src:

img-src 'self' data: blob: https://images.unsplash.com

Development mode: Next.js dev server uses eval() for Fast Refresh. Add 'unsafe-eval' only in development:

const isDev = process.env.NODE_ENV === 'development';
const scriptSrc = isDev
  ? `'self' 'unsafe-eval' 'nonce-${nonce}'`
  : `'self' 'nonce-${nonce}' 'strict-dynamic'`;

Vercel Deployment

When deploying to Vercel, middleware runs at the Edge. Use crypto.randomUUID() (available in Edge Runtime) for nonce generation instead of Node.js crypto.randomBytes().

Use Case

Next.js is one of the most popular React frameworks for production applications. Whether building a marketing site, SaaS dashboard, or e-commerce platform with Next.js, implementing CSP through middleware provides the strongest security. The nonce-based approach works seamlessly with Next.js Server Components, App Router, and Vercel Edge deployment.

Try It — CSP Header Generator

Open full tool