vercel/next.js · error · BailoutToCSRError
NEXT_DYNAMIC_BAILOUT_REASON
Error message
NEXT_DYNAMIC_BAILOUT_REASON
What it means
This error is thrown when next/dynamic is used inside a Server Component with ssr: false during static prerendering. Because ssr: false means the component must only render on the client, but a Server Component prerender cannot bail out to CSR without a boundary, Next.js throws BailoutToCSRError with the reason NEXT_DYNAMIC_BAILOUT_REASON to force the tree to become client-rendered.
Source
Thrown at packages/next/src/shared/lib/lazy-dynamic/dynamic-bailout-to-csr.tsx:31
const getNextDynamicBailoutReason = createReactBrowserBailoutReason.bind(
null,
NEXT_DYNAMIC_BAILOUT_REASON
)
/**
* Signals during server rendering that this subtree should be client-rendered.
*/
export function BailoutToCSRForNextDynamic({
children,
}: BailoutToCSRForNextDynamicProps) {
if (process.env.__NEXT_EXPERIMENTAL_REACT_BROWSER_BAILOUT) {
// @ts-expect-error TODO: Update @types/react-dom to include the reason argument.
use(browser(getNextDynamicBailoutReason))
return children
}
if (typeof window === 'undefined') {
throw new BailoutToCSRError(NEXT_DYNAMIC_BAILOUT_REASON)
}
return children
}
View on GitHub (pinned to 89d017eac4)
Solutions
- Move the dynamic(..., { ssr: false }) call into a client component (add 'use client' at the top of the file that calls next/dynamic) and import that wrapper from the server component
- Remove ssr: false if the component can be server-rendered, using a mounted-state check for client-only APIs instead
- If the dynamic usage must stay in server code, ensure the component is under a Suspense boundary and that you're on a version that supports the bailout rather than throwing
Example fix
// before (server component page.tsx)
import dynamic from 'next/dynamic'
const Chart = dynamic(() => import('./Chart'), { ssr: false })
export default function Page() { return <Chart /> }
// after
// ChartWrapper.tsx
'use client'
import dynamic from 'next/dynamic'
const Chart = dynamic(() => import('./Chart'), { ssr: false })
export default function ChartWrapper() { return <Chart /> }
// page.tsx (server)
import ChartWrapper from './ChartWrapper'
export default function Page() { return <ChartWrapper /> } Defensive patterns
Strategy: validation
Validate before calling
// Convention check before adding next/dynamic with ssr:false in server code:
import fs from 'node:fs'
const src = fs.readFileSync('app/page.tsx', 'utf8')
if (src.includes("ssr: false") && !src.trimStart().startsWith("'use client'")) {
throw new Error('ssr:false dynamic import must live in a client component')
} Type guard
function isClientComponent(source: string): boolean {
return /^['"]use client['"]/.test(source.trimStart())
} Try / catch
// Not applicable: thrown during static prerender at build time; fix structure instead of catching.
Prevention
- Never call dynamic(..., { ssr: false }) in files without 'use client'
- Create a wrapper client component per client-only widget
- Prefer useEffect + mounted state for client-only browser APIs over ssr:false in server trees
- Run next build in CI to catch prerender bailouts early
When it happens
Trigger: Using dynamic(() => import('...'), { ssr: false }) inside a Server Component (a file without 'use client'); a shared component/library that internally uses next/dynamic with ssr: false being imported by a server layout/page; wrapping the ssr:false dynamic import in a Suspense boundary so the bailout propagates during prerender.
Common situations: Adding a client-only widget (map, editor, chart) with next/dynamic ssr:false directly to a server page; upgrading Next.js 13/14 where ssr:false in Server Components became disallowed; libraries like react-map-gl wrappers using ssr:false imported from server code; static export setups.
Related errors
- ${expression}
- createRevalidateDuringRenderError (revalidate* called during
- Route "${route}": Unexpected cache miss after cache warming
AI-assisted analysis of vercel/next.js@89d017eac4 (2026-08-27).
Data as JSON: /api/errors/6aad79b1293c09dc.
Report an issue: GitHub.