DEV Community

pante5ter
pante5ter

Posted on

Hydration Errors in Next.js: What They Mean and How to Fix Them for Good

Few errors waste more time than a hydration mismatch. The app mostly works, the console screams "Text content does not match server-rendered HTML," and the cause is rarely where you're looking. Here's what's actually happening and how to fix it permanently.

What hydration is (in one paragraph)

Next.js renders your page to HTML on the server and sends it down so the user sees content fast. Then React "hydrates" that HTML in the browser — it re-runs your components and attaches event handlers, expecting the output to match the HTML the server already produced. A hydration error means the browser render and the server render disagreed. React notices, throws away the mismatched part, and re-renders on the client — which is slow and can cause flicker.

The usual culprits

1. Time, dates, and random values

The classic. The server renders the date at one moment; the browser renders it a few hundred milliseconds later — different text, instant mismatch. Math.random() does the same.

Fix: don't render time-sensitive or random values during SSR. Render a stable placeholder on the server and fill in the live value after mount (in useEffect), or compute the value once on the server and pass it down as a fixed prop.

2. window, localStorage, navigator

These don't exist on the server. If a component reads localStorage to decide what to render, the server (which has no localStorage) renders one thing and the browser renders another.

Fix: read browser-only APIs inside useEffect, which only runs client-side. Render the same neutral output on both server and first client paint, then update after mount.

3. Invalid HTML nesting

A div inside a p, or a p inside a p, gets "corrected" by the browser's HTML parser — so the DOM the browser builds differs from what React expected. This one is sneaky because the code looks fine.

Fix: keep your markup valid. Don't nest block elements inside a paragraph; don't put a div inside a button. If a third-party component does this, that's often the real source.

4. Browser extensions

Some extensions inject attributes or elements into the DOM before React hydrates (Grammarly is a frequent offender). The page is fine; the extension changed the HTML.

Fix: this one isn't your bug. Confirm by reproducing in an incognito window with extensions off. For inputs, suppressHydrationWarning on the specific element is an acceptable, targeted escape hatch.

5. Conditionals based on client-only state

Rendering a component only when isLoggedIn is true, where isLoggedIn comes from localStorage, is the same problem dressed up — the server can't know the value, so it renders the wrong branch.

Fix: gate client-only UI behind a "mounted" flag, or load that state through something the server can read too (a cookie, for example).

The reliable pattern: the "mounted" gate

For anything that legitimately differs between server and client, this small hook removes the whole class of errors:

const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return <Placeholder />; // same on server + first paint
return <LiveThing />;                  // only after hydration
Enter fullscreen mode Exit fullscreen mode

Use it sparingly — overusing it means giving up SSR benefits — but for genuinely client-only widgets it's the clean fix.

How to debug efficiently

  1. Read the diff. React's error usually shows expected vs received text. That points straight at the offending value.
  2. Check incognito. If it vanishes with extensions off, it's an extension, not you.
  3. Binary-search the tree. Comment out halves of the page until the warning disappears.

Hydration errors feel mysterious, but they almost always reduce to one rule: the server and the first client render must produce identical HTML. Once you internalise that, the fix for each case is obvious.


Fighting a hydration error or another Next.js bug that's eaten your afternoon? I fix React/Next.js bugs same-day, with a plain note on the root cause so it doesn't come back — vengstudio.online.

Top comments (0)