All posts
nextjsssrdebugging

document is not defined — What It Means and How to Fix It

"document is not defined" explained — why it happens, a real code example that triggers it, and the exact fix.

SR

Suhail Roushan

August 6, 2026

·
3 min read
·
0 views

"document is not defined" is a ReferenceError thrown when code tries to access the browser's document object in a runtime where it doesn't exist.

What "document is not defined" Means

The document object is the entry point to the DOM in browsers. When JavaScript executes outside a browser environment — or before the browser has finished parsing — that object simply doesn't exist, so referencing it throws this error.

Why It Happens

The two most common causes:

  1. Server-side rendering (SSR): In Node.js or Next.js server components, there is no DOM. Code that references document during server-side execution crashes immediately.
  2. Module scope confusion: In Next.js or Vite, code at the top level of a module runs during import. If that code touches document before the browser has loaded the page, you get this error.

Example Code That Triggers It

// This file runs both on the server and in the browser (e.g., a Next.js page)
const theme = document.querySelector('html').dataset.theme;
console.log(theme);

Run that in Node.js directly:

node script.js
# ReferenceError: document is not defined

How to Fix It

Guard the access so it only runs in the browser:

// Safe version — checks for browser environment
const getTheme = () => {
  if (typeof window === 'undefined') {
    return 'light'; // default on server
  }
  return document.querySelector('html').dataset.theme;
};

In React/Next.js, use useEffect or dynamic imports with ssr: false to defer DOM access until after hydration:

import { useEffect, useState } from 'react';

function Theme() {
  const [theme, setTheme] = useState('light');
  
  useEffect(() => {
    setTheme(document.querySelector('html').dataset.theme);
  }, []);
  
  return <p>{theme}</p>;
}

The fix works because useEffect runs exclusively in the browser after the component mounts — never on the server.

Common Mistakes That Cause This

  1. Calling document at module top-level in a universal component. Any file imported by both server and client bundles will execute that line on the server. Move DOM access inside functions, effects, or event handlers.

  2. Using document directly in a Next.js getServerSideProps or API route. These run purely in Node.js. If you need browser data there, pass it from the client via a fetch call instead.

When Should You Worry About This?

You should worry when this error appears in client-side only code — that means your build tooling is misconfigured. A Next.js page that crashes with "document is not defined" during client navigation indicates a module-level side effect that shouldn't exist. In plain browser JavaScript (no framework), this error means you're loading the script in the <head> without defer — move it to the end of <body> or add defer to the script tag.

The one thing to check first: search your codebase for document at the top level of any file that gets imported by both server and client bundles. That's the culprit nine times out of ten.

Related posts

Written by Suhail Roushan — Full-stack developer. More posts on AI, Next.js, and building products at suhailroushan.com/blog.

Get in touch