The "window is not defined" error means your JavaScript code is referencing the browser's global window object in an environment where it doesn't exist, like Node.js or during server-side rendering.
What "window is not defined" Means
This is a ReferenceError thrown when JavaScript tries to access window but the runtime doesn't have it. In browsers, window is the global object. In Node.js, the global object is global — so window simply doesn't exist there.
Why It Happens
Three causes cover 95% of cases:
- Running browser code in Node.js — you wrote code for the browser, then ran it with
node script.js. Node has nowindow. - Server-side rendering (SSR) — in Next.js, Nuxt, or Remix, your component code executes on the server first, where
windowis absent. - TypeScript strict mode — the TypeScript compiler flags
windowwhenlibdoesn't include"DOM", even in browser-targeted builds.
Example Code That Triggers It
// app.ts — run with: node app.ts
function getViewportWidth(): number {
return window.innerWidth; // ReferenceError: window is not defined
}
console.log(getViewportWidth());
Run this with Node.js and you'll get the exact error. The same code works in a browser console, which is what makes it confusing.
How to Fix It
For Node.js, check if window exists before using it:
function getViewportWidth(): number {
if (typeof window !== "undefined") {
return window.innerWidth;
}
return 0; // fallback for server-side
}
For Next.js SSR, use the useEffect hook or dynamic imports to defer browser-only code:
"use client"; // Next.js 13+ App Router
import { useEffect, useState } from "react";
export default function ViewportWidth() {
const [width, setWidth] = useState<number>(0);
useEffect(() => {
setWidth(window.innerWidth); // runs only in the browser
}, []);
return <p>Width: {width}px</p>;
}
The fix works because typeof window !== "undefined" is a safe check — typeof on an undeclared variable returns "undefined" instead of throwing. And useEffect only executes client-side in React.
Common Mistakes That Cause This
Mistake 1: Accessing window at module top-level. Even with the typeof guard, top-level code runs on the server during SSR. Move browser interactions into lifecycle hooks or event handlers.
Mistake 2: Forgetting the "DOM" lib in TypeScript. Your tsconfig.json might exclude browser globals. Add "lib": ["ES2020", "DOM"] to fix type-checking errors that point to window.
When Should You Worry About This?
You should worry when the error appears in production logs from server-side code, not just your local terminal. If a Next.js API route or a serverless function throws this, it means browser-only code leaked into your server bundle — that's a real architecture bug, not a dev convenience issue. In browsers, this error almost never appears unless you're using a web worker or a sandboxed iframe.
Next time you see "window is not defined," check whether the file that threw it is running on a server or client first — that single question resolves 80% of cases instantly.