/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:
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.cjsOutput
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
'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 windowchecks in render: the server takes one branch, the browser the other. Use the effect pattern above, ornext/dynamicwithssr: falsefor 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 andtimeZonediffers between server and visitor. - Browser extensions that inject attributes; test in a private window.
Sources
Related pages
glossary · reactWhat is hydration in React and Next.js?Hydration is when React attaches event handlers and state to HTML rendered on the server, making a server-rendered page interactive without rebuilding it.errors · reactEach child in a list should have a unique "key" propReact warns Each child in a list should have a unique "key" prop when map() returns elements without key. Use a stable id from your data, not the index.errors · reactError: Too many re-renders. React limits the number of renders to prevent an infinite loop.React throws Too many re-renders when a component sets state during render, often onClick={setCount(1)} instead of onClick={() => setCount(1)}. How to fix it.