Deep diveJul 30, 20266 min read

Next.js hydration errors: the five causes, ranked

Dates, window checks, invalid HTML nesting, random IDs and browser extensions. In that order.

Hydration fails when the HTML the server rendered differs from what React renders on the first client pass. React 19 prints a diff; read it before guessing.

react-hydration-errorErrorHydration failed: server/client mismatchThe 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>.

1 · Time and locale

Post.tsx
// ✕ server renders UTC, browser renders local time
<span>{new Date(post.date).toLocaleString()}</span>

// ✓ render a stable string, or format after mount
<time dateTime={post.date} suppressHydrationWarning>{formatUTC(post.date)}</time>

2 · Branching on window

typeof window !== "undefined" is false on the server and true in the browser, so the first client render differs by definition. Move client-only values into useEffect.

3 · Invalid nesting

A <div> inside a <p> is repaired by the browser’s HTML parser before React sees it. The DOM no longer matches.

4 · Random IDs

Use useId() instead of Math.random() or a counter. It is stable across server and client.

5 · Browser extensions

Password managers and translators inject attributes into <html> and <body>. If the diff only shows attributes you never wrote, test in a clean profile before changing code.