This React hydration error FAQ answers the questions developers search for most, in a few sentences each. Every answer links to the page that covers the topic in full, with the exact error strings, before-and-after code and a way to find every instance in your app.
What is a hydration error in React?
Hydration is the step where React attaches to HTML the server already rendered, instead of creating the DOM from scratch. React expects its first client render to produce exactly that HTML. A hydration error means it did not: React 19 then throws away the mismatching part and renders it again on the client, or, for an attribute in a production build, keeps the wrong value without telling you. React hydration errors explains the behavior in detail.
What causes hydration errors in Next.js?
Render code that produces different output on the server and in the browser.
The usual suspects are the current time, random values, locale or timezone
formatting, browser-only APIs such as window and localStorage, invalid HTML
nesting, and things outside your code: browser extensions, scripts that run
before hydration, and CDNs that rewrite HTML. See the
common causes of hydration errors and the
Next.js guide.
How do I fix "Hydration failed because the initial UI does not match what was rendered on the server"?
This is React 18's error for a mismatch it could not recover from in place:
Hydration failed because the initial UI does not match what was rendered on the server.Find the element that differs, then make the first client render produce what
the server rendered: read browser-only values in useEffect, pass values the
server computed as props, and fix invalid nesting. The full walkthrough is in
hydration failed: initial UI does not match.
What does "the server rendered HTML didn't match the client" mean in React 19?
It is React 19's wording of the same problem:
Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client.React discarded the server HTML for the affected tree and rendered it again in the browser. The page still works, but the server rendering was wasted and any state in that tree is reset. See the server rendered HTML didn't match the client.
How do I find which component is causing a hydration error?
In development, React's error message includes a component stack, and the
Next.js dev overlay shows it for the page you have open. Production builds only
give a minified code. npx hydration-proof test loads every route and reports
the element's selector, the component, the server and client values and, in
development builds, the file and line. Debug hydration errors
shows each approach.
Is it safe to use suppressHydrationWarning?
It is safe on a single element whose own text or attributes are meant to differ, such as a timestamp or a theme class that an inline script sets before hydration. React then keeps the server value and does not patch it. It is not a fix for a real mismatch: it hides the bug, and the user keeps the wrong value. See when suppressHydrationWarning is safe.
Why is suppressHydrationWarning not working?
It only works one level deep: it covers the element's own attributes and its direct text, not its child elements. It also cannot hide structural differences, such as an element that exists on one side only. Put it on the element whose text differs, and fix the cause of anything structural. The suppressHydrationWarning guide has examples of both.
Can I ignore or disable hydration errors in Next.js?
React has no setting that turns the check off for a page. You can silence one
element with suppressHydrationWarning, or render a component only in the
browser with next/dynamic and ssr: false. Neither fixes the mismatch, so
use them for content that is meant to differ. For known findings you are not
fixing yet, hydration-proof has ignore rules with a reason
and an expiry date.
Why do I only get hydration errors in production?
Production is where the two renders drift apart most: cached pages rendered hours earlier, real users' locales, timezones and browser extensions, and CDNs that minify HTML. Production builds also report only a minified code, and React 19 does not report attribute mismatches there at all. See hydration errors only in production.
Can browser extensions cause hydration errors?
Yes. Extensions such as Grammarly, ColorZilla and password managers add attributes or elements to the page before React hydrates, and React reports the difference as if your code caused it. Nothing needs to change in your app; test in a clean browser profile. hydration-proof reports these changes as HP4002, an info finding. See browser extension hydration errors.
What does "Extra attributes from the server: cz-shortcut-listen" mean?
cz-shortcut-listen is an attribute the ColorZilla extension adds to <body>.
React 18 found it in the DOM but not in what it rendered, and warned about it.
It is not a bug in your code, and it does not appear for users without the
extension. See extra attributes from the server.
How do I show dates without a hydration mismatch?
Read the clock once on the server and pass the value down as a prop, so both
renders format the same number. Format with an explicit locale and timeZone,
never the runtime's defaults. For live values such as countdowns, render a
placeholder and fill it in from useEffect. The
date and time guide has code for each fix.
Why does toLocaleString() cause a hydration error?
Without arguments, toLocaleString() uses the default locale and timezone of
the runtime: the server's on the server and the visitor's in the browser. The
same date then renders as two different strings. Pass an explicit locale and
timeZone on both sides. See locale-dependent formatting.
How do I use localStorage in Next.js without a hydration error?
localStorage only exists in the browser, so a value read from it during render
differs from what the server rendered. Render a neutral value first and read
storage in useEffect, or use useSyncExternalStore with a
getServerSnapshot that returns the server's value. See
localStorage hydration errors.
How do I fix the next-themes hydration error?
The server cannot know the visitor's theme. next-themes sets the theme on
<html> with a script before hydration, so add suppressHydrationWarning to
<html>, as its README says. Anything that renders from useTheme(), such as
a theme toggle, must wait until the component has mounted. See
theme hydration errors.
What is minified React error #418?
It is the production code for a hydration mismatch. In React 18 it stands for "Hydration failed because the initial UI does not match what was rendered on the server." In React 19 it stands for "Hydration failed because the server rendered HTML didn't match the client," and it also covers text mismatches. See React error #418.
What's the difference between React errors #418, #423 and #425?
| Code | React 18 | React 19 |
|---|---|---|
| #418 | Hydration failed because the initial UI does not match what was rendered on the server. | Hydration failed because the server rendered HTML didn't match the client. |
| #423 | There was an error while hydrating; the entire root switches to client rendering. | React recovered by client rendering the entire root. |
| #425 | Text content does not match server-rendered HTML. | Folded into #418 |
In React 18 you often see all three for one bug: #425 for the text, #418 for the failed hydration, and #423 for the fallback to client rendering. See minified React error codes.
Why can't a <div> be inside a <p> in React?
The HTML parser closes a <p> as soon as a block element such as <div>
starts. The browser's DOM then no longer matches the tree React rendered, and
hydration fails. Use a <span>, or make the outer element a <div>. See
div cannot be a descendant of p.
How do I disable SSR for one component in Next.js?
Import it with next/dynamic and ssr: false from a Client Component; the App
Router does not allow ssr: false in Server Components. The component then
renders only in the browser, after hydration. See
next/dynamic with ssr: false and
client-only components.
Does useEffect run on the server?
No. Effects run only in the browser, after React has committed the first
render. That is why reading browser values in useEffect keeps the first client
render identical to the server HTML. See
useEffect and two-pass rendering.
What is the difference between hydrateRoot and createRoot?
hydrateRoot attaches React to HTML the server already rendered and reuses
those DOM nodes, so the first client render must match it. createRoot clears
whatever is inside the container the first time it renders, then builds the DOM
itself, so there is nothing to mismatch. Server-rendered and statically
generated apps must use hydrateRoot. See
what is hydration in React.
Do hydration errors hurt SEO or performance?
They cost performance: React 19 renders the mismatching tree again on the client, which is slower and resets its state. They can also change what users and crawlers see, because the content after hydration is not the content the server sent, and attribute mismatches in production stay wrong. See hydration errors and SEO.
Why does useId cause a hydration mismatch?
useId builds each id from the component's position in the tree, so it only
matches when the server and the client render the same tree. A branch that
renders on one side only shifts the ids after it. Several React roots on one
page also need different identifierPrefix values. See
generated ids that differ.
How do I test for hydration errors in Playwright or CI?
Listening for console errors in a Playwright test catches what React reports,
but production builds only print minified codes, and React 19 never reports
attribute mismatches there. npx hydration-proof test uses Playwright to load
every route, compares the server HTML with the hydrated page, and exits with
code 1 when it finds a problem. See Playwright and
detect hydration errors in CI.
Is there an ESLint rule that catches hydration errors?
Yes. eslint-plugin-hydration-proof has 15 rules for render code, such as
no-date-in-render and
no-storage-in-initial-render.
The purity rule in eslint-plugin-react-hooks flags calls such as
Date.now() and Math.random() in render. Lint rules cannot see extensions,
CDNs or data differences, so pair them with a runtime test. See
all ESLint rules.