ReferenceError: window is not defined

Next.js · updated 2026-11-03

Thrown during server rendering or the build, when code touches window, document or localStorage. Server Components and the server pass of Client Components both run in Node.js, where those globals don't exist.

 ⨯ ReferenceError: window is not defined
    at Chart (./src/components/Chart.tsx:9:17)
    at renderWithHooks (node_modules/react-dom/cjs/react-dom-server.node.development.js:5728:16)
    at renderIndeterminateComponent (node_modules/react-dom/cjs/react-dom-server.node.development.js:5781:15) {
  digest: '1846296187'
}

Quick fix

Run browser-only code after the component mounts: inside useEffect, an event handler, or a component loaded with next/dynamic and ssr: false. A 'use client' directive alone is not enough, because Client Components still render once on the server.

  1. Find the line in the stack trace that reads window, document, localStorage or navigator.
  2. If it runs while rendering, move it into useEffect so it only runs in the browser.
  3. If a library touches window when it is imported, load the component that uses it with next/dynamic and ssr: false.
  4. For code that must run in both places, guard it with typeof window !== 'undefined'.
typescript
'use client';
import { useEffect, useState } from 'react';
import dynamic from 'next/dynamic';

// A library that reads window at import time
const Chart = dynamic(() => import('./Chart'), { ssr: false });

export function Dashboard() {
  const [width, setWidth] = useState(0);
  useEffect(() => setWidth(window.innerWidth), []); // runs only in the browser
  return <Chart width={width} />;
}

Why it happens

Assuming 'use client' means browser-only

Client Components are pre-rendered to HTML on the server and then hydrated. Anything they do in the render body, including reading window, runs on the server first.

A library that reads window at import time

Some chart, map and editor packages check window when the module loads. Importing them at the top of any file that renders on the server fails before your component code runs.

Reading localStorage or matchMedia to pick initial state

Setting useState from localStorage in the component body runs on the server. Start with a server-safe default and read the stored value in useEffect.

Other fixes

  • A typeof window check in the render body avoids the crash but can cause a hydration mismatch if the server and client output differ: prefer useEffect.
  • For a whole page that only works in the browser, render a shell on the server and load the interactive part with next/dynamic.

Same error, other wording

  • ReferenceError: document is not defined
  • ReferenceError: localStorage is not defined
  • ReferenceError: navigator is not defined

Let your coding agent catch the next one

Runheed records this error in production with the stack trace, the breadcrumbs before it and the agent session that shipped the code, and serves it to Claude Code, Cursor or any MCP client. With it connected, you can ask:

> Find the window is not defined errors from server rendering, show me which component and import trigger each one, and move that code into useEffect or a dynamic import with ssr: false.

Plans from $29/moSee what your agent readsSee the setupCancel any time from the billing portal

Related errors

References: Next.js docs: Client Components, Next.js docs: lazy loading with next/dynamic