Hydration Proof

Search documentation

Find a page or section

Debugging hydration errors

From a vague console message to the line that caused it.

To debug a hydration error, find the element that differs, compare the server's value with the client's, and let that difference tell you the cause. React 19's development build prints a diff that does most of this. For production-only errors and silent attribute mismatches, you need the server HTML and a tool that compares it for you.

How to debug a hydration error, step by step

A typical React debug hydration error session takes five steps:

  1. Reproduce it in a clean browser profile. Open the page in a guest or private window with extensions turned off. If the error disappears, an extension caused it (see browser extensions).
  2. Run a development build. Production builds only print minified codes. Development builds print the component stack and, in React 19, a diff.
  3. Read the diff. Lines starting with + are what the client rendered, lines starting with - are what the server sent.
  4. Find the component. Follow the component stack under the diff to your file.
  5. Name the cause from the two values, then fix it and check the page again.

Read the diff React prints

React 19 logs a single error with a diff of the mismatch and the tree around it. This is the example from the React 19 release post:

Uncaught Error: Hydration failed because the server rendered HTML didn't match the client. As a result this tree will be regenerated on the client. This can happen if an SSR-ed Client Component used:
...
https://react.dev/link/hydration-mismatch
 
  <App>
    <span>
+    Client
-    Server

React 18 printed separate warnings instead, for example Warning: Text content did not match. Server: "Server" Client: "Client", followed by "Hydration failed because the initial UI does not match what was rendered on the server."

The two values usually give the cause away:

The values look likeLikely cause
Two timestamps a few hundred milliseconds apartThe clock
The same time, hours apartTimezone
1,234.5 and 1.234,5Locale
Two random-looking tokensRandom values or ids
light and darkTheme
Desktop and mobile markupMedia queries
Different records or countsData
Class names like sc-a1b2 in a different orderCSS-in-JS

How to find which component causes a hydration error

When the diff is not enough, narrow it down:

  1. Follow the component stack. The first component in it that you wrote is usually the one to look at.
  2. Compare the server HTML with the DOM. "View page source" shows the HTML the server sent. The Elements panel shows the DOM after React changed it. Search both for the text around the error.
  3. Turn JavaScript off. In DevTools, disable JavaScript and reload: what you see is the server's version of the page.
  4. Bisect. Comment out half of the page's children, or return null from them, and reload. Keep the half that still errors and repeat. A mismatch in a layout shows up on every page, one in a page component only there.
  5. Check shared components. A header or footer that reads the clock, a cookie banner or a theme toggle breaks every route at once.

Rule out browser extensions

Extensions such as password managers and grammar checkers add attributes to <body> or <input> before React hydrates. The diff then shows attributes you never wrote, for example cz-shortcut-listen="true" or data-new-gr-c-s-check-loaded. Nothing in your code is wrong: test in a clean profile, and read browser extension hydration errors for the list of attributes.

Debug hydration errors in Next.js

When you debug a hydration error, Next.js adds its own tools on top of React's:

  • The dev overlay. Since Next.js 15, hydration errors show the source code of the error with suggestions. Since Next.js 16.2, the overlay labels the diff with a + Client / - Server legend (Next.js 16.2 release notes).
  • The error page. Next.js links the message to its hydration error page, which lists the usual causes.

The overlay shows one page at a time, while you browse, in development. Next.js dev overlay compared covers what it does not see.

Debug hydration mismatch reports in production

Production builds print Minified React error #418 with no element and no diff, and React 19 production builds do not report attribute mismatches at all. To trace them:

  1. Build and start the app locally in production mode, with the server's timezone and locale.
  2. Turn on browser source maps (productionBrowserSourceMaps: true in Next.js) to map minified code to your files.
  3. Test development and production builds side by side and compare what each reports.

React hydration errors only in production walks through each step.

hydration-proof loads every route, compares the server HTML with what React renders, and prints the element, both values, the component, the source line and the likely cause:

npx hydration-proof test
npx hydration-proof test --mode both  # development and production builds
npx hydration-proof test --probe  # prove the cause

With --probe, each page with a value mismatch is loaded again with one thing changed at a time: the clock, the random seed, the locale, the timezone, the theme, the viewport or storage. The factor that changes the value is the cause (probes).

While you work on a page, npx hydration-proof dev opens the app with an overlay that shows the findings of every page you open, highlights the element and opens the source line in your editor (dev overlay).