Oliver White
7 May 2026 · 6 min read
React requires eval() in development mode for error stack reconstruction and DevTools integration. In production, the compiled React build uses no eval at all. This means a Content Security Policy that correctly excludes 'unsafe-eval' in production will break the development server — unless it is gated on NODE_ENV. Here is what that error looks like and how the gate works:
Error: eval() is not supported in this environment. React requires eval() in development mode for various debugging features like reconstructing callstacks. To enable eval(), pass a CSP value of `unsafe-eval` in the `script-src` directive.
In development mode, React uses eval() to reconstruct component call stacks for error messages, enable React DevTools integration, and produce meaningful stack traces. None of this happens in production — the production build of React is compiled down to plain function calls with no eval.
| Environment | React mode | Uses eval()? | CSP requirement |
|---|---|---|---|
| Development | Development build with debugging | Yes | unsafe-eval required |
| Production | Minified production build | No | unsafe-eval must be removed |
The wrong fix is to add 'unsafe-eval' to your production CSP and move on. This defeats the purpose of having a CSP — eval() is the primary mechanism through which XSS attacks execute arbitrary JavaScript.
Wrong: always allow eval
Right: gate on NODE_ENV
You can verify your production CSP is correct by checking the response headers in browser DevTools → Network → select any page request → Response Headers → Content-Security-Policy. The string should not contain 'unsafe-eval' on the live site.
CSP is one of six security headers applied on every response through the Next.js middleware. The middleware runs on the edge before any server component or API route executes:
| Header | Value | Protects against |
|---|---|---|
| Content-Security-Policy | Allowlist of sources | XSS, injection, data exfiltration |
| X-Frame-Options | DENY | Clickjacking |
| X-Content-Type-Options | nosniff | MIME-type sniffing attacks |
| Strict-Transport-Security | max-age=63072000; includeSubDomains; preload | Protocol downgrade, MITM |
| Referrer-Policy | strict-origin-when-cross-origin | Referrer header leakage |
| Permissions-Policy | camera=(), microphone=(), geolocation=() | Capability abuse |
All six are set in a single applySecurityHeaders() function called inside the NextAuth middleware wrapper. This guarantees they're applied to every response — including API routes, page responses, and redirects — without needing to add them to each route individually.
Built with this methodology
React's development build requires eval() for stack reconstruction and DevTools. Your production CSP must not include 'unsafe-eval'. The fix is a NODE_ENV gate in middleware.ts — one conditional, correct in both environments.
From the build log