Skip to content

/errors/nextjs/hydration-failed

Hydration failed because the server rendered HTML didn't match the client

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash)updated 2026-10-20
tool
Next.js
exit code
0
versions
React 19, Next.js 15, Next.js 16
os
any

React 19 (and therefore Next.js) reports Hydration failed because the server rendered text didn't match the client. As a result this tree will be regenerated on the client. (or …rendered HTML…) when the markup produced on the server is not what the first render in the browser produces. React then throws away the server HTML for that subtree and renders it again on the client.

Reproduce it

Server HTML says 1, the client renders 2, as happens with Date.now() or random values. jsdom stands in for the browser:

bash
npm init -y >/dev/null
npm install --silent --no-audit --no-fund react@19 react-dom@19 jsdom >/dev/null 2>&1
cat > hydrate.cjs <<'JS'
const { JSDOM } = require("jsdom");
const dom = new JSDOM("<!doctype html><div id=root><p>Server time: 1</p></div>");
global.window = dom.window; global.document = dom.window.document;
const React = require("react");
const { hydrateRoot } = require("react-dom/client");
const App = () => React.createElement("p", null, "Server time: ", 2);
hydrateRoot(document.getElementById("root"), React.createElement(App), {
  onRecoverableError: (err) => console.log(err.message.split("\n")[0]),
});
setTimeout(() => process.exit(0), 500);
JS
node hydrate.cjs

Output

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:

Fix: render browser-only values after mount

jsx
'use client';
import { useEffect, useState } from 'react';

export function LocalTime() {
  const [time, setTime] = useState(null);       // same on server and first client render
  useEffect(() => setTime(new Date().toLocaleTimeString()), []);
  return <span>{time ?? '—'}</span>;
}

Other common causes

  • typeof window checks in render: the server takes one branch, the browser the other. Use the effect pattern above, or next/dynamic with ssr: false for whole components.
  • Invalid nesting: <p><div>…</div></p> or <a> inside <a>; the browser rearranges the DOM before React compares it.
  • Locale and time zone: toLocaleString() without a fixed locale and timeZone differs between server and visitor.
  • Browser extensions that inject attributes; test in a private window.

Sources