Next.jsRunbook 0/4 done
react-hydration-error

Next.js Error react-hydration-error: Hydration failed: server/client mismatch

Error✕ Not retryable · fix the payloadClient
TL;DR · 10-second read

The HTML React rendered on the server differs from the first client render, so React discards and re-renders the tree. Move time-, locale- or window-dependent values into useEffect and fix invalid nesting like <div> inside <p>.

Identify: does your log match?

What you see · exact log / response
Error: Hydration failed because the server rendered text didn't match the client. As a result this tree will be regenerated on the client. This can happen if a SSR-ed Client Component used:

- A server/client branch `if (typeof window !== 'undefined')`.
- Variable input such as `Date.now()` or `Math.random()` which changes each time it's called.
- Date formatting in a user's locale which doesn't match the server.
- External changing data without sending a snapshot of it along with the HTML.
- Invalid HTML tag nesting.

It can also happen if the client has a browser extension installed which messes with the HTML before React loaded.

https://react.dev/link/hydration-mismatch

  <LastSeen>
    <span>
+     10/23/2026, 2:14:07 PM
-     23/10/2026, 14:14:07
  1. High

    Time or locale dependent output

    new Date().toLocaleString() renders in the server's timezone and locale, then differently in the browser.

  2. High

    Browser-only branches during render

    typeof window checks or localStorage reads during render produce different markup on server and client.

  3. Medium

    Invalid HTML nesting

    <div> inside <p>, or <a> inside <a>: the browser's parser fixes the DOM, so it no longer matches React's tree.

Fix

Render client-only values after mount

✕ Broken · Next.js
'use client';
export function LastSeen({ at }: { at: string }) {
  return <span>{new Date(at).toLocaleString()}</span>;
}
✓ Fixed · Next.js
'use client';
import { useEffect, useState } from 'react';

export function LastSeen({ at }: { at: string }) {
  const [text, setText] = useState(at.slice(0, 10)); // stable on server + first client render
  useEffect(() => setText(new Date(at).toLocaleString()), [at]);
  return <time dateTime={at}>{text}</time>;
}

The first client render matches the server; the locale-specific value is applied after hydration.

Verify: reproduce it on purpose

Reproduce locally · Next.js
$ npx create-next-app@latest hydration-demo --yes && cd hydration-demo && printf "export default function Page(){return <p>{Math.random()}</p>}\n" > app/page.tsx && npm run dev

Run it against a dev environment to trigger react-hydration-error on purpose and test your error handler.

Prevent

  • Use suppressHydrationWarning only for single unavoidable text nodes (e.g. timestamps).
  • Test in an incognito window to rule out extensions.
  • Run the HTML validator on SSR output for nesting bugs.

FAQ

Can browser extensions cause hydration errors?

Yes. Extensions like Grammarly or password managers inject attributes into <body> or inputs before React hydrates. Reproduce in a clean profile first.

Is suppressHydrationWarning a real fix?

Only for one element's text or attributes, one level deep. It hides the warning but the content still differs.

Do hydration errors break production?

React recovers by client-rendering, but you lose SSR performance for that subtree and may see layout flicker.

Related errors

Last verified 2026-10-23 · Source: Next.js /errors directory (vercel/next.js) · Official docs ↗ · ~40,500 searches/mo