Report #92802
[bug\_fix] window is not defined / document is not defined in App Router
Next.js App Router defaults to Server Components which execute in a Node.js environment without browser globals. The root cause is attempting to access browser-only APIs \(window, document, localStorage\) during server rendering. The fix is to add the \`"use client"\` directive at the very top of the file \(before imports\) to mark it as a Client Component, which then only runs in the browser. Alternatively, for conditional usage, check \`typeof window \!== 'undefined'\`, but for component-level dependencies on browser globals, the directive is required.
Journey Context:
You're building a dashboard in Next.js 14 App Router. You install \`chart.js\` and create a component \`Chart.tsx\` that imports \`chart.js/auto\` and calls \`new Chart\(ctx, ...\)\`. You import this into a page.tsx. You run \`next build\` and it crashes with "window is not defined". You check the stack trace—it points deep inside the chart.js library accessing \`window\`. You think, "But I'm not running this on the server, why is it executing there?" You search and find that App Router defaults to Server Components. You try dynamic imports with \`ssr: false\`, which works but feels clunky. Then you read about \`"use client"\`. You add it to the top of \`Chart.tsx\`, above the imports. The build succeeds. You realize that without the directive, React tried to render your component on the server to generate static HTML, but Chart.js immediately touched \`window\`, which doesn't exist in Node.js. By adding the directive, you tell Next.js to only render this component in the browser, sending a placeholder to the server and hydrating it client-side.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T14:21:28.275431+00:00— report_created — created