In this brief article, I will explain why you get the “window is not defined error” or “document is not defined error” in Next.JS and how you can fix it.
Why am I seeing this error?
I was building an order management system for restaurants and decided that Next was the best framework to do just that because I didn’t want to worry about routing and still wanted to use React.
In my case, I had this error show up twice for two reasons
- I needed to send a CSRF token with my payload to an API I was building and using ‘document.cookie’ triggered the error.
- I was using ‘react-apexcharts’ for data visualization — which was making an internal call to the ‘window’ object.
At first, I thought it was a bug in my code, or that I was referencing the window object too early before my page was mounted and tried pushing it back a few seconds with setTimeout, but to no avail.
Basically, the reason we can’t access the ‘window’ or ‘document’ object is because of Next.JS’ Server-Side Rendering (SSR) capabilities. Next.js renders our pages on the server and serves these pages in chunks.
The “window” and “document” are client-side APIs and because Next pre-renders each page — server-side, we can’t access those APIs simply because they don’t exist (server-side) yet.
2. How do I fix this error
Do lazy-loading and dynamic imports ring any bells?
To prevent server side rendering in NextJS, you must use dynamic imports to lazy-load the component that you want rendered in the client.
I scoured the web for a solution, and after referring back to the docs I found out about dynamic imports and how they can help.
As you may have noticed in line 3 I am setting the SSR option to false causing this to be imported at runtime (client-side) instead of build-time(server-side).
When trying to access the window/document object directly (without third-party packages), there are two approaches.
- Store the window object in a state variable for later (not recommended)
- Use Client Components
You can hack your way around this issue using the useEffect hook. See how I implemented a solution here using useEffect and useState
Be warned, this is a hack and although it resolves this error, I don’t recommend this approach. A much better way to do this is by using Client Components. By default, all components are Server Components in Next.js unless declared otherwise.
So how do we make a Client component? Client components are no different from Server components save for one exception. Client components have the ‘use-client’ string declaration above all imports, telling Next.js to treat that file as a Client component rather that a Server component.
'use client'
// at the top of the page
// before any imports
... // imports
// you don't need to use dynamic imports in Client components
export const MyComponent = ({ props }) =>{
return(
<div>...</div>
)
}
export default MyComponent;
Now that we’ve identified the causes and fix for this error, you should have no problem tracing the cause of this error in your own codebase, particularly if you’re using any third-party packages referencing ‘window’ or ‘document’.
I hope you found this article helpful. Thanks for reading, and happy coding!
In Plain English 🚀
Thank you for being a part of the In Plain English community! Before you go:
- Be sure to clap and follow the writer ️👏️️
- Follow us: X | LinkedIn | YouTube | Discord | Newsletter
- Visit our other platforms: CoFeed | Differ
- More content at PlainEnglish.io
