Run code only on server or client in Next.js

By

Learn how to run code only on the server or only on the client in Next.js by checking typeof window, and how Next.js strips server-only blocks from bundles.

~~~

In your page components, you can execute code only on the server side or only on the client side, by checking the window property. window only exists inside the browser, so it tells you exactly where the code is running.

Why does this matter? Next.js pre-renders your pages on the server. The same component code runs twice: once in Node.js to generate the HTML, and once in the browser. On the server there is no window, no document, no localStorage. Touch any of them during server rendering and the page crashes.

Running code only on the server

Check that window is undefined:

if (typeof window === 'undefined') {
}

and add the server-side code in that block.

Running code only on the client

Similarly, you can execute client-side code only by checking that window exists:

if (typeof window !== 'undefined') {
}

A realistic case: reading a saved theme from localStorage. Unguarded, this crashes the server render. Guarded, it runs only in the browser:

let theme = 'light'
if (typeof window !== 'undefined') {
  theme = localStorage.getItem('theme') || 'light'
}

JS Tip: We use the typeof operator here because we can’t detect a value to be undefined in other ways. We can’t do if (window === undefined) because we’d get a “window is not defined” runtime error

Bundles get smaller too

Next.js, as a build-time optimization, also removes the code that uses those checks from bundles. A client-side bundle will not include the content wrapped into a if (typeof window === 'undefined') {} block.

This is nice for two reasons. Your users download less JavaScript, and server-only code (say, something reading an environment secret) never ships to the browser.

Watch out for hydration mismatches

One pitfall. If you use these checks to render different markup on server and client, React will complain. The HTML generated on the server won’t match what the client renders, and you get a hydration warning, sometimes with visible glitches.

The fix: don’t branch the markup on typeof window. For client-only logic that affects what’s rendered, put it in a useEffect instead. Effects never run on the server, so the first client render matches the server HTML, and your browser-only code runs right after.

Tagged: Next.js · All topics
~~~

Related posts about next: