Skip to content
Latchkey

Gatsby "window is not defined" building static HTML in CI

Gatsby renders every page to static HTML in Node during the build, where window and document do not exist. A component or imported module references a browser global at render time and crashes the build.

What this error means

gatsby build fails in the "Building static HTML for pages" stage with "WebpackError: ReferenceError: window is not defined" and a list of affected pages.

gatsby
failed Building static HTML for pages - 0.5s

  WebpackError: ReferenceError: window is not defined

  - useViewport.js:4 ... const w = window.innerWidth

Common causes

Browser globals used during render

A component reads window, document, or localStorage at module load or in render, which runs server-side during the build.

A third-party module that assumes a browser

An imported library touches window on import, so merely importing it breaks SSR even if you never call it.

How to fix it

Guard browser-only access

Check for the browser before touching globals, and read them inside effects that run only on the client.

src/hooks/useViewport.js
useEffect(() => {
  const w = window.innerWidth; // client only
}, []);

Exclude a browser-only module from SSR

Null-loader the offending module during the build (html stage) so it is not evaluated server-side.

gatsby-node.js
exports.onCreateWebpackConfig = ({ stage, actions }) => {
  if (stage === 'build-html') {
    actions.setWebpackConfig({ module: { rules: [
      { test: /bad-browser-lib/, use: ['null-loader'] },
    ] } });
  }
};

How to prevent it

  • Access browser globals only inside effects or event handlers.
  • Guard with typeof window !== "undefined" for module-level reads.
  • Null-loader libraries that assume a browser during build-html.

Frequently asked questions

What causes ""window is not defined" (Gatsby SSR)"?
A component reads window, document, or localStorage at module load or in render, which runs server-side during the build.
How do I fix "window is not defined" (Gatsby SSR)?
Check for the browser before touching globals, and read them inside effects that run only on the client.

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card