~4 min read • Updated Oct 26, 2025
Setting CSP Without Using Nonces
If your application doesn’t rely on inline scripts, you can configure CSP headers directly in next.config.js:
const cspHeader = `
default-src 'self';
script-src 'self' 'unsafe-eval' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' blob: data:;
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
`
module.exports = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: cspHeader.replace(/\n/g, ''),
},
],
},
]
},
}Using Subresource Integrity (SRI)
Next.js offers experimental support for SRI, allowing hash-based CSP enforcement without dynamic rendering.
Enabling SRI
Add the following to next.config.js:
const nextConfig = {
experimental: {
sri: {
algorithm: 'sha256',
},
},
}
module.exports = nextConfigCSP Configuration with SRI
SRI works independently by adding integrity hashes to your scripts. You can keep your CSP strict:
const cspHeader = `
default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' blob: data:;
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
`
module.exports = {
experimental: {
sri: {
algorithm: 'sha256',
},
},
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: cspHeader.replace(/\n/g, ''),
},
],
},
]
},
}Benefits of SRI Over Nonces
- Supports static generation
- Compatible with CDN caching
- Improved performance without SSR per request
- Build-time security with cryptographic hashes
Limitations of SRI
- Experimental feature
- Only works with Webpack (not Turbopack)
- Only supported in App Router
- Only applies at build time
Development vs Production
Development Environment
In development, you may need 'unsafe-eval' for debugging tools:
const isDev = process.env.NODE_ENV === 'development'
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}' 'strict-dynamic' ${isDev ? "'unsafe-eval'" : ''};
style-src 'self' ${isDev ? "'unsafe-inline'" : `'nonce-${nonce}'`};
...
`Production Deployment
- Ensure Proxy runs on all required routes
- Allow Next.js static assets in your CSP
- Add third-party domains to your CSP policy
Third-Party Scripts and CSP
To use services like Google Tag Manager:
import { GoogleTagManager } from '@next/third-parties/google'
import { headers } from 'next/headers'
export default async function RootLayout({ children }) {
const nonce = (await headers()).get('x-nonce')
return (
<html lang="en">
<body>
{children}
<GoogleTagManager gtmId="GTM-XYZ" nonce={nonce} />
</body>
</html>
)
}Example CSP for Google Scripts
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}' 'strict-dynamic' https://www.googletagmanager.com;
connect-src 'self' https://www.google-analytics.com;
img-src 'self' data: https://www.google-analytics.com;
`Common CSP Violations
- Inline styles: Use CSS-in-JS libraries that support nonces or move styles to external files
- Dynamic imports: Ensure they’re allowed in
script-src - WebAssembly: Add
'wasm-unsafe-eval'if needed - Service workers: Add appropriate policies for worker scripts
Version History
| Version | Changes |
|---|---|
| v14.0.0 | Experimental SRI support added for hash-based CSP |
| v13.4.20 | Recommended for proper nonce handling and CSP header parsing |
Conclusion
If your application doesn’t require nonce-based CSP, you can use SRI and direct CSP headers to maintain security while benefiting from static rendering and CDN caching. This approach is ideal for performance-focused applications with build-time integrity needs.
Written & researched by Dr. Shahin Siami