search
Javascript star Featured

How to Fix window is not defined Error in JavaScript and React

Learn how to fix the common 'window is not defined' error in JavaScript, React, Next.js, and Node.js. Complete guide with solutions for browser and server-side rendering issues.

person By Gautam Sharma
calendar_today January 2, 2026
schedule 13 min read
JavaScript React Next.js Node.js Error Handling SSR Browser APIs

The ‘window is not defined’ error is one of the most common issues developers face when working with JavaScript, especially in React applications and server-side rendering environments. This error occurs when code tries to access the window object in environments where it doesn’t exist, such as Node.js servers.

This comprehensive guide explains how to fix window is not defined error in various JavaScript environments with practical solutions and real-world examples.


What Causes the window is not defined Error?

The window object is a browser-specific global object that represents the browser window or frame. It’s only available in browser environments, not in server-side JavaScript runtimes like Node.js. The error occurs when:

  • Server-side rendering (SSR) in React/Next.js applications
  • Node.js applications trying to access browser APIs
  • Universal JavaScript applications running in multiple environments
  • Testing environments that don’t simulate browser globals

Common Error Messages:

  • ReferenceError: window is not defined
  • Uncaught ReferenceError: window is not defined
  • window is not defined at Object...
  • TypeError: Cannot read property 'localStorage' of undefined

Environment-Specific Solutions

React and Next.js SSR Issues

When using server-side rendering frameworks like Next.js, the window object is not available during server rendering.

❌ Problem Scenario:

// This will cause an error in Next.js SSR
function MyComponent() {
  const [isBrowser, setIsBrowser] = useState(false);

  useEffect(() => {
    // This runs on client but can cause hydration issues
    setIsBrowser(true);
    console.log(window.innerWidth); // Error during SSR
  }, []);

  return (
    <div>
      {isBrowser && <p>Window width: {window.innerWidth}</p>}
    </div>
  );
}

✅ Solution: Check for Browser Environment

// Safe approach for Next.js and React SSR
function MyComponent() {
  const [windowSize, setWindowSize] = useState(null);

  useEffect(() => {
    // Only run in browser environment
    if (typeof window !== 'undefined') {
      const handleResize = () => {
        setWindowSize({
          width: window.innerWidth,
          height: window.innerHeight
        });
      };

      // Set initial size
      handleResize();

      // Add event listener
      window.addEventListener('resize', handleResize);

      // Cleanup
      return () => window.removeEventListener('resize', handleResize);
    }
  }, []);

  if (!windowSize) {
    // Render fallback during SSR
    return <div>Loading...</div>;
  }

  return (
    <div>
      <p>Window width: {windowSize.width}px</p>
      <p>Window height: {windowSize.height}px</p>
    </div>
  );
}

Node.js Environment Issues

In Node.js, the window object doesn’t exist, so any attempt to access it will result in an error.

❌ Problem Scenario:

// This will fail in Node.js
function getNodeWindow() {
  return window.location; // ReferenceError: window is not defined
}

✅ Solution: Environment Detection

// Safe Node.js implementation
function getEnvironmentInfo() {
  if (typeof window !== 'undefined') {
    // Browser environment
    return {
      isBrowser: true,
      location: window.location,
      navigator: window.navigator
    };
  } else {
    // Node.js environment
    return {
      isBrowser: false,
      location: null,
      userAgent: 'Node.js Environment'
    };
  }
}

Solution 1: Dynamic Import for Browser-Only Code

Use dynamic imports to load browser-specific code only on the client side.

// pages/my-page.js (Next.js example)
import { useState, useEffect } from 'react';

function MyPage() {
  const [component, setComponent] = useState(null);

  useEffect(() => {
    // Dynamic import for browser-only components
    import('../components/BrowserSpecificComponent')
      .then((module) => {
        setComponent(module.default);
      })
      .catch((error) => {
        console.error('Error loading component:', error);
      });
  }, []);

  return (
    <div>
      {component ? <component /> : <p>Loading browser component...</p>}
    </div>
  );
}

export default MyPage;

Using Next.js Dynamic Import with SSR Disabled:

// components/BrowserOnlyComponent.js
import { useEffect, useState } from 'react';
import dynamic from 'next/dynamic';

// Dynamically import with SSR disabled
const BrowserOnlyComponent = dynamic(
  () => import('../components/WindowDependentComponent'),
  { ssr: false }
);

function MyPage() {
  return (
    <div>
      <h1>My Page</h1>
      <BrowserOnlyComponent />
    </div>
  );
}

export default MyPage;

Solution 2: Window Detection Helper Functions

Create reusable helper functions to safely access window properties.

// utils/windowHelpers.js
export const isBrowser = () => typeof window !== 'undefined';

export const getWindowDimensions = () => {
  if (isBrowser()) {
    return {
      width: window.innerWidth,
      height: window.innerHeight
    };
  }
  return { width: 0, height: 0 };
};

export const getLocalStorage = (key) => {
  if (isBrowser() && window.localStorage) {
    return window.localStorage.getItem(key);
  }
  return null;
};

export const setLocalStorage = (key, value) => {
  if (isBrowser() && window.localStorage) {
    window.localStorage.setItem(key, value);
  }
};

export const getWindowLocation = () => {
  if (isBrowser()) {
    return window.location;
  }
  return null;
};

// Usage example
function ResponsiveComponent() {
  const [dimensions, setDimensions] = useState(getWindowDimensions());

  useEffect(() => {
    if (isBrowser()) {
      const handleResize = () => {
        setDimensions(getWindowDimensions());
      };

      window.addEventListener('resize', handleResize);
      return () => window.removeEventListener('resize', handleResize);
    }
  }, []);

  return (
    <div>
      <p>Width: {dimensions.width}px</p>
      <p>Height: {dimensions.height}px</p>
    </div>
  );
}

Solution 3: Custom React Hook for Window Access

Create a custom hook to safely access window properties in React components.

// hooks/useWindow.js
import { useState, useEffect } from 'react';

export const useWindow = () => {
  const [windowInfo, setWindowInfo] = useState({
    isBrowser: false,
    width: 0,
    height: 0,
    location: null,
    navigator: null
  });

  useEffect(() => {
    if (typeof window !== 'undefined') {
      setWindowInfo({
        isBrowser: true,
        width: window.innerWidth,
        height: window.innerHeight,
        location: window.location,
        navigator: window.navigator
      });

      const handleResize = () => {
        setWindowInfo(prev => ({
          ...prev,
          width: window.innerWidth,
          height: window.innerHeight
        }));
      };

      window.addEventListener('resize', handleResize);

      return () => window.removeEventListener('resize', handleResize);
    }
  }, []);

  return windowInfo;
};

// Usage in component
function MyComponent() {
  const { isBrowser, width, height } = useWindow();

  if (!isBrowser) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <p>Window width: {width}px</p>
      <p>Window height: {height}px</p>
    </div>
  );
}

Solution 4: Server-Side Rendering with Conditional Rendering

Implement proper conditional rendering for SSR applications.

// components/SSRCompatibleComponent.js
import { useState, useEffect } from 'react';

function SSRCompatibleComponent() {
  const [isClient, setIsClient] = useState(false);

  useEffect(() => {
    // Set client state after component mounts
    setIsClient(true);
  }, []);

  // Render different content based on environment
  if (!isClient) {
    // Server-side or initial render
    return (
      <div className="skeleton-loader">
        <p>Loading window-dependent content...</p>
      </div>
    );
  }

  // Client-side render with window access
  return (
    <div>
      <h2>Window Properties</h2>
      <p>URL: {window.location.href}</p>
      <p>Width: {window.innerWidth}px</p>
      <p>Height: {window.innerHeight}px</p>
      <p>User Agent: {window.navigator.userAgent}</p>
    </div>
  );
}

export default SSRCompatibleComponent;

Solution 5: Polyfill and Mock Implementation

Create mock implementations for testing and server environments.

// utils/windowPolyfill.js
export const createWindowMock = () => {
  return {
    location: {
      href: 'http://localhost',
      origin: 'http://localhost',
      pathname: '/',
      search: '',
      hash: ''
    },
    innerWidth: 1024,
    innerHeight: 768,
    localStorage: {
      getItem: () => null,
      setItem: () => {},
      removeItem: () => {},
      clear: () => {}
    },
    sessionStorage: {
      getItem: () => null,
      setItem: () => {},
      removeItem: () => {},
      clear: () => {}
    },
    navigator: {
      userAgent: 'Mock Browser',
      platform: 'Mock Platform'
    },
    addEventListener: () => {},
    removeEventListener: () => {},
    scrollTo: () => {}
  };
};

// For testing environments
export const setupWindowMock = () => {
  if (typeof window === 'undefined') {
    global.window = createWindowMock();
    global.document = {
      createElement: () => ({}),
      addEventListener: () => {},
      removeEventListener: () => {}
    };
  }
};

// Usage in tests
// test-utils.js
import { setupWindowMock } from './utils/windowPolyfill';

setupWindowMock();

Solution 6: Build Configuration Fixes

Configure your build system to handle browser globals properly.

For Next.js:

// next.config.js
module.exports = {
  webpack: (config, { isServer }) => {
    if (!isServer) {
      config.resolve.fallback = {
        ...config.resolve.fallback,
        fs: false, // Disable fs module on client
      };
    }
    return config;
  },
  // Handle dynamic imports
  experimental: {
    esmExternals: 'loose'
  }
};

For Webpack:

// webpack.config.js
module.exports = {
  // ... other config
  resolve: {
    fallback: {
      "path": false,
      "fs": false,
      "crypto": false
    }
  },
  // Define browser globals
  plugins: [
    new webpack.DefinePlugin({
      'typeof window': JSON.stringify(typeof window),
    }),
  ],
};

For Vite:

// vite.config.js
export default {
  define: {
    global: 'globalThis',
  },
  // Handle different environments
  ssr: {
    noExternal: ['some-module-that-needs-to-be-bundled']
  }
};

Solution 7: Framework-Specific Implementations

React with useEffect:

// components/WindowAwareComponent.js
import { useState, useEffect } from 'react';

function WindowAwareComponent() {
  const [windowData, setWindowData] = useState(null);

  useEffect(() => {
    // This only runs in browser
    if (typeof window !== 'undefined') {
      const data = {
        width: window.innerWidth,
        height: window.innerHeight,
        url: window.location.href,
        userAgent: window.navigator.userAgent
      };
      
      setWindowData(data);
      
      const handleResize = () => {
        setWindowData(prev => ({
          ...prev,
          width: window.innerWidth,
          height: window.innerHeight
        }));
      };
      
      window.addEventListener('resize', handleResize);
      
      return () => window.removeEventListener('resize', handleResize);
    }
  }, []);

  if (!windowData) {
    return <div>Detecting window properties...</div>;
  }

  return (
    <div>
      <h3>Window Information</h3>
      <p>Width: {windowData.width}px</p>
      <p>Height: {windowData.height}px</p>
      <p>URL: {windowData.url}</p>
    </div>
  );
}

Next.js with getServerSideProps:

// pages/window-info.js
export async function getServerSideProps({ req }) {
  // Server-side code - no window access
  const userAgent = req.headers['user-agent'] || 'Unknown';
  
  return {
    props: {
      userAgent,
      isServer: true
    }
  };
}

export default function WindowInfoPage({ userAgent, isServer }) {
  const [clientInfo, setClientInfo] = useState(null);

  useEffect(() => {
    // Client-side code - window is available
    if (typeof window !== 'undefined') {
      setClientInfo({
        width: window.innerWidth,
        height: window.innerHeight,
        url: window.location.href
      });
    }
  }, []);

  return (
    <div>
      <h1>Window Information</h1>
      <p>Server detected user agent: {userAgent}</p>
      {clientInfo ? (
        <div>
          <p>Client window width: {clientInfo.width}px</p>
          <p>Client window height: {clientInfo.height}px</p>
          <p>Client URL: {clientInfo.url}</p>
        </div>
      ) : (
        <p>Loading client information...</p>
      )}
    </div>
  );
}

Solution 8: Testing Environment Setup

Configure your testing environment to handle window access properly.

Jest Setup:

// jest.setup.js
// Mock window object for tests
Object.defineProperty(global, 'window', {
  value: {
    location: {
      href: 'http://localhost',
      origin: 'http://localhost',
      pathname: '/',
      search: '',
      hash: ''
    },
    innerWidth: 1024,
    innerHeight: 768,
    localStorage: {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
      clear: jest.fn()
    },
    sessionStorage: {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
      clear: jest.fn()
    },
    navigator: {
      userAgent: 'Jest Test Environment'
    },
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    scrollTo: jest.fn()
  },
  writable: true
});

Object.defineProperty(global, 'document', {
  value: {
    createElement: jest.fn(() => ({})),
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    body: {}
  },
  writable: true
});

Testing Components:

// components/WindowAwareComponent.test.js
import { render, screen } from '@testing-library/react';
import WindowAwareComponent from './WindowAwareComponent';

describe('WindowAwareComponent', () => {
  test('renders without crashing', () => {
    render(<WindowAwareComponent />);
    expect(screen.getByText(/Detecting window properties/i)).toBeInTheDocument();
  });

  test('handles window detection', () => {
    render(<WindowAwareComponent />);
    // Component should handle both browser and non-browser environments
  });
});

Debugging Strategies

1. Environment Detection:

// Debug environment and window availability
function debugWindowEnvironment() {
  const envInfo = {
    isBrowser: typeof window !== 'undefined',
    isNode: typeof process !== 'undefined' && process.versions && process.versions.node,
    hasWindow: typeof window !== 'undefined',
    hasDocument: typeof document !== 'undefined',
    windowType: typeof window,
    userAgent: typeof window !== 'undefined' ? window.navigator?.userAgent : 'N/A'
  };
  
  console.log('Environment Info:', envInfo);
  return envInfo;
}

debugWindowEnvironment();

2. Safe Window Access Pattern:

// Universal window access pattern
const safeWindowAccess = (callback) => {
  if (typeof window !== 'undefined') {
    return callback(window);
  } else {
    console.warn('Window object not available in this environment');
    return null;
  }
};

// Usage
safeWindowAccess((win) => {
  console.log('Window width:', win.innerWidth);
});

Performance Considerations

Efficient Window Event Handling:

// Optimized window event handling
class WindowEventManager {
  constructor() {
    this.events = new Map();
    this.isBrowser = typeof window !== 'undefined';
  }

  addListener(event, handler, options = {}) {
    if (!this.isBrowser) {
      console.warn(`Cannot add ${event} listener: window not available`);
      return;
    }

    const wrappedHandler = options.debounce 
      ? this.debounce(handler, options.debounce) 
      : handler;

    window.addEventListener(event, wrappedHandler);
    this.events.set(event, { handler: wrappedHandler, original: handler });
  }

  removeListener(event) {
    if (!this.isBrowser || !this.events.has(event)) return;

    const eventInfo = this.events.get(event);
    window.removeEventListener(event, eventInfo.handler);
    this.events.delete(event);
  }

  debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
      const later = () => {
        clearTimeout(timeout);
        func(...args);
      };
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  }

  destroy() {
    for (const [event, eventInfo] of this.events) {
      window.removeEventListener(event, eventInfo.handler);
    }
    this.events.clear();
  }
}

// Usage
const windowManager = new WindowEventManager();
windowManager.addListener('resize', () => {
  console.log('Window resized');
}, { debounce: 250 });

Security Considerations

Safe Window Property Access:

// Secure window property access
function secureWindowAccess(propertyPath) {
  // Validate input to prevent prototype pollution
  if (typeof propertyPath !== 'string' || propertyPath.includes('__proto__') || propertyPath.includes('constructor')) {
    throw new Error('Invalid property path');
  }

  if (typeof window === 'undefined') {
    return null;
  }

  // Safely navigate the property path
  try {
    return propertyPath.split('.').reduce((obj, prop) => obj && obj[prop], window);
  } catch (error) {
    console.error('Error accessing window property:', error);
    return null;
  }
}

// Usage
const userAgent = secureWindowAccess('navigator.userAgent');
const localStorage = secureWindowAccess('localStorage');

Common Mistakes to Avoid

1. Direct Window Access in SSR:

// ❌ Don't do this in SSR
function BadComponent() {
  const width = window.innerWidth; // Error during SSR
  return <div>Width: {width}</div>;
}

2. Forgetting to Check Environment:

// ❌ Don't do this
if (window.localStorage) {
  // This will error in Node.js
}

3. Not Cleaning Up Event Listeners:

// ❌ Don't forget cleanup
useEffect(() => {
  window.addEventListener('resize', handleResize);
  // Missing cleanup function!
}, []);

Alternative Solutions

Using Modern JavaScript Features:

// Optional chaining for safe access
const windowWidth = typeof window !== 'undefined' ? window?.innerWidth : null;
const userAgent = typeof window !== 'undefined' ? window?.navigator?.userAgent : null;

// Nullish coalescing for defaults
const width = windowWidth ?? 0;
const agent = userAgent ?? 'Unknown';

Feature Detection Instead of Browser Detection:

// Check for specific features rather than browser object
const hasLocalStorage = () => {
  try {
    const storage = window.localStorage;
    return typeof storage === 'object';
  } catch (e) {
    return false;
  }
};

const hasResizeObserver = () => {
  return typeof ResizeObserver !== 'undefined';
};

// Usage
if (hasLocalStorage()) {
  // Safe to use localStorage
}

Troubleshooting Checklist

When encountering the window is not defined error:

  1. Identify Environment: Determine if code runs on server or client
  2. Check Imports: Verify no server-side code accesses browser APIs
  3. Review SSR Setup: Ensure proper server-side rendering configuration
  4. Validate Build Tools: Confirm build configuration handles browser globals
  5. Test in Both Environments: Verify code works in browser and Node.js
  6. Check Framework Documentation: Review framework-specific SSR guidelines
  7. Review Dependencies: Ensure third-party libraries support SSR

Conclusion

The ‘window is not defined’ error is a common issue when working with JavaScript in different environments, particularly when implementing server-side rendering. By using environment detection, conditional rendering, and proper build configurations, you can ensure your code works seamlessly across both browser and server environments.

The key to resolving this error is understanding that the window object is browser-specific and implementing defensive programming practices to safely access browser APIs only when they’re available. Whether you’re working with React, Next.js, or vanilla JavaScript, the solutions provided in this guide will help you handle the window object appropriately across different execution environments.

Remember to always check for the existence of browser-specific objects before accessing them, and implement proper fallbacks for server-side rendering scenarios.

Gautam Sharma

About Gautam Sharma

Full-stack developer and tech blogger sharing coding tutorials and best practices

Related Articles

Javascript

How to Fix Uncaught ReferenceError: Buffer is not defined Error in JavaScript and React

Learn how to fix the common 'Buffer is not defined' error in JavaScript, React, Next.js, and browser environments. Complete guide with solutions for Node.js and browser compatibility.

January 2, 2026
Javascript

How to Fix setTimeout Undefined Issue in JavaScript: Expert Solutions

Discover how to resolve the common setTimeout undefined error in JavaScript. Learn practical fixes for browser and Node.js environments with detailed examples and troubleshooting tips.

January 2, 2026
Javascript

Fix: document is not defined error in JavaScript

Learn how to fix the 'document is not defined' error in JavaScript applications. This comprehensive guide covers server-side rendering, Node.js, and browser compatibility.

January 2, 2026