# React hydration error FAQ

> React hydration error FAQ: short answers to the most asked questions, from error #418 and suppressHydrationWarning to useEffect, useId and next-themes.

Source: https://hydration.jscrate.dev/docs/faq
Last updated: 2026-09-18

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](https://hydration.jscrate.dev/docs/guides/react-hydration-error) 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](https://hydration.jscrate.dev/docs/causes) and the
[Next.js guide](https://hydration.jscrate.dev/docs/frameworks/nextjs).

## 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:

```text
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](https://hydration.jscrate.dev/docs/errors/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:

```text
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](https://hydration.jscrate.dev/docs/errors/hydration-failed-server-rendered-html-didnt-match-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](https://hydration.jscrate.dev/docs/guides/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](https://hydration.jscrate.dev/docs/guides/suppresshydrationwarning).

## 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](https://hydration.jscrate.dev/docs/guides/suppresshydrationwarning) 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](https://hydration.jscrate.dev/docs/ignoring) 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](https://hydration.jscrate.dev/docs/guides/hydration-error-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](https://hydration.jscrate.dev/docs/issues/hp4002), an info finding. See
[browser extension hydration errors](https://hydration.jscrate.dev/docs/causes/extension).

## 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](https://hydration.jscrate.dev/docs/errors/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](https://hydration.jscrate.dev/docs/causes/time) 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](https://hydration.jscrate.dev/docs/causes/locale).

## 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](https://hydration.jscrate.dev/docs/causes/storage).

## 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](https://hydration.jscrate.dev/docs/causes/theme).

## 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](https://hydration.jscrate.dev/docs/errors/minified-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](https://hydration.jscrate.dev/docs/errors/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](https://hydration.jscrate.dev/docs/errors/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](https://hydration.jscrate.dev/docs/guides/next-dynamic-ssr-false) and
[client-only components](https://hydration.jscrate.dev/docs/guides/client-only-component).

## 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](https://hydration.jscrate.dev/docs/guides/useeffect-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](https://hydration.jscrate.dev/docs/guides/what-is-hydration).

## 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](https://hydration.jscrate.dev/docs/guides/hydration-errors-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](https://hydration.jscrate.dev/docs/causes/unstable-id).

## 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](https://hydration.jscrate.dev/docs/playwright) and
[detect hydration errors in CI](https://hydration.jscrate.dev/docs/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`](https://hydration.jscrate.dev/docs/rules/no-date-in-render) and
[`no-storage-in-initial-render`](https://hydration.jscrate.dev/docs/rules/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](https://hydration.jscrate.dev/docs/rules).

## Related

- [All React hydration error messages](https://hydration.jscrate.dev/docs/errors)
- [Common causes of hydration errors](https://hydration.jscrate.dev/docs/causes)
- [Debug a hydration error step by step](https://hydration.jscrate.dev/docs/guides/debug-hydration-errors)
- [Quick start with hydration-proof](https://hydration.jscrate.dev/docs/quick-start)
- [Hydration error tools compared](https://hydration.jscrate.dev/docs/comparison)
