{"record":{"id":"6aad79b1293c09dc","repo":"vercel/next.js","slug":"next-dynamic-bailout-reason","errorCode":null,"errorMessage":"NEXT_DYNAMIC_BAILOUT_REASON","messagePattern":"NEXT_DYNAMIC_BAILOUT_REASON","errorType":"exception","errorClass":"BailoutToCSRError","httpStatus":null,"severity":"error","filePath":"packages/next/src/shared/lib/lazy-dynamic/dynamic-bailout-to-csr.tsx","lineNumber":31,"sourceCode":"const getNextDynamicBailoutReason = createReactBrowserBailoutReason.bind(\n  null,\n  NEXT_DYNAMIC_BAILOUT_REASON\n)\n\n/**\n * Signals during server rendering that this subtree should be client-rendered.\n */\nexport function BailoutToCSRForNextDynamic({\n  children,\n}: BailoutToCSRForNextDynamicProps) {\n  if (process.env.__NEXT_EXPERIMENTAL_REACT_BROWSER_BAILOUT) {\n    // @ts-expect-error TODO: Update @types/react-dom to include the reason argument.\n    use(browser(getNextDynamicBailoutReason))\n    return children\n  }\n\n  if (typeof window === 'undefined') {\n    throw new BailoutToCSRError(NEXT_DYNAMIC_BAILOUT_REASON)\n  }\n\n  return children\n}\n","sourceCodeStart":13,"sourceCodeEnd":36,"githubUrl":"https://github.com/vercel/next.js/blob/89d017eac43ebf4742ed2b58d3c1373b70283b69/packages/next/src/shared/lib/lazy-dynamic/dynamic-bailout-to-csr.tsx#L13-L36","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (server component page.tsx)\nimport dynamic from 'next/dynamic'\nconst Chart = dynamic(() => import('./Chart'), { ssr: false })\nexport default function Page() { return <Chart /> }\n\n// after\n// ChartWrapper.tsx\n'use client'\nimport dynamic from 'next/dynamic'\nconst Chart = dynamic(() => import('./Chart'), { ssr: false })\nexport default function ChartWrapper() { return <Chart /> }\n\n// page.tsx (server)\nimport ChartWrapper from './ChartWrapper'\nexport default function Page() { return <ChartWrapper /> }","handlingStrategy":"validation","validationCode":"// Convention check before adding next/dynamic with ssr:false in server code:\nimport fs from 'node:fs'\nconst src = fs.readFileSync('app/page.tsx', 'utf8')\nif (src.includes(\"ssr: false\") && !src.trimStart().startsWith(\"'use client'\")) {\n  throw new Error('ssr:false dynamic import must live in a client component')\n}","typeGuard":"function isClientComponent(source: string): boolean {\n  return /^['\"]use client['\"]/.test(source.trimStart())\n}","tryCatchPattern":"// Not applicable: thrown during static prerender at build time; fix structure instead of catching.\n","preventionTips":["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"],"tags":["nextjs","next-dynamic","ssr-false","server-component","prerender","bailout"],"backgroundTag":"prerender-bailout-to-csr","analyzedSha":"89d017eac43ebf4742ed2b58d3c1373b70283b69","analyzedAt":"2026-08-27T11:26:12.396Z","contentChangedAt":"2026-08-27T11:26:12.396Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}