Overview
Hydration is the client step that makes server-rendered HTML interactive: the framework re-runs the component tree in the browser, checks it against the existing DOM, reuses the nodes, and attaches handlers. A page that looks ready but ignores clicks on slow phones is waiting on hydration. Ship less client JavaScript or hydrate only interactive parts. A page with no interactivity needs no hydration and no JavaScript.
Rules
- Shrink the work: Astro islands (
client:*directives) hydrate only interactive components; server-component output never hydrates, only Client Components do; Suspense boundaries hydrate independently (suspense-boundary); Qwik skips hydration by resuming server state on first interaction (resumability). - Make the first client render match the server HTML. Mismatches come from
windoworlocalStoragechecks during render,Date.now(),Math.random(), locale or timezone differences, client-only auth state, invalid HTML nesting, and browser extensions that alter the DOM. - React may recover by client-rendering the affected part, but it does not guarantee attribute differences are patched and handlers can attach to the wrong elements. Treat every mismatch as a bug.
- Read browser-only values in
useEffectafter mount (a second render), useuseIdfor IDs, and usesuppressHydrationWarningonly for unavoidable text such as timestamps (one level deep).
function Clock() {
const [time, setTime] = useState(""); // same on server and first client render
useEffect(() => setTime(new Date().toLocaleTimeString()), []);
return <time>{time}</time>;
}Related
- ssr: the source of HTML that hydrates.
- ssg: build-time HTML that hydrates the same way.
- server-component: output that never hydrates.
- suspense-boundary: independent hydration units.
- react: rendering lifecycle.
- astro-islands: partial hydration.