Docusaurus generates static HTML files for every route by rendering your React theme components in a Node.js environment using React DOM Server. This process — called static site generation (SSG), or equivalently server-side rendering (SSR) in Docusaurus terminology — runs before the browser is ever involved. The resulting HTML files are what users and search engines see first; the browser then hydrates them into a full single-page application.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/facebook/docusaurus/llms.txt
Use this file to discover all available pages before exploring further.
Docusaurus uses “SSR” and “SSG” interchangeably in its codebase. Strictly speaking it is a static site generator: it pre-renders HTML at build time and deploys the files to a CDN. There is no server dynamically rendering pages at request time, which distinguishes it from frameworks like Next.js in SSR mode.
How the SSR pass works
Duringdocusaurus build, the bundler produces two separate outputs from the same theme source:
Server bundle
Compiled for Node.js. Used during the SSG pass to call
renderToString() on every route. Produces the .html files in build/. Never shipped to users.Client bundle
Compiled for browsers. Split per route and loaded after the HTML file arrives. Provides all the interactive and dynamic behaviour of the site.
window, no document, and no browser globals of any kind. Any component that references these values directly will throw a ReferenceError at build time:
Hydration and the SPA transition
These HTML files are the first thing that arrives in the user’s browser. The main content is already visible — no JavaScript needs to run before the page is readable. Afterwards, the browser downloads and executes the client bundle. In a client-side-only React app, the HTML file contains only an empty<div id="root"> and React builds the entire DOM from scratch in JavaScript. In a Docusaurus SSR app, React finds a fully-built DOM already in place and only needs to attach event listeners and synchronise its virtual DOM model. This step is called hydration.
Escape hatches for browser-only code
Docusaurus provides several safe patterns for components that genuinely require the browser environment.<BrowserOnly>
Wrap browser-dependent components with <BrowserOnly> to render nothing during SSR and only render the real component after the first client render:
<BrowserOnly> must be a function that returns an element, not the element itself. This prevents the React renderer from evaluating browser globals during SSR even when the component is ultimately not rendered.
useIsBrowser
When you need to conditionally compute a value — but don’t need a completely different component tree — use the useIsBrowser hook. It returns false during SSR and true after the first client render:
useEffect
useEffect callbacks never run during SSR. Use them for side effects that must happen after mount, such as subscribing to browser events, measuring DOM elements, or importing browser-only libraries:
ExecutionEnvironment
The ExecutionEnvironment module provides a canUseDOM flag that is true in the browser and false during SSR. Use it for imperative browser code outside of React rendering — for example, in client modules or utility functions. Do not use it to conditionally return different JSX, or you will hit the hydration mismatch problem described above.
a-client-module.js
Comparison of escape hatches
When to use BrowserOnly
When to use BrowserOnly
Use
<BrowserOnly> when an entire component cannot render server-side at all — for example, a rich code editor that imports window-dependent libraries. Provide a meaningful fallback so the layout does not shift when the real component mounts.When to use useIsBrowser
When to use useIsBrowser
Use
useIsBrowser when the component structure is the same in both environments but a specific value or class name depends on the browser. Keeps the component tree stable, minimising hydration risk.When to use useEffect
When to use useEffect
Use
useEffect for side effects that interact with the DOM or browser APIs after mount, such as attaching event listeners, reading scroll position, or lazy-loading a third-party script.When to use ExecutionEnvironment.canUseDOM
When to use ExecutionEnvironment.canUseDOM
Use
ExecutionEnvironment.canUseDOM in non-React code — client modules, utility files, plugin-provided client-side JS — where you need a synchronous, non-hook guard around browser API calls.process.env.NODE_ENV exception
process.env.NODE_ENV is the one “Node global” that is safe to use in theme code. Webpack replaces it at bundle time with the literal string 'development' or 'production', allowing dead-code elimination:
- Development build
- Production build
process.env.NODE_ENV is never actually read as a Node global in the browser bundle.