React Hydration and Rendering Boundaries
Server-side rendering sends HTML that users can see before JavaScript loads. Hydration is the step where React, running in the browser, walks that HTML, builds its component tree, and attaches event handlers so the page becomes interactive. Hydration requires the first client render to produce exactly the same output as the server. When it does not — a timestamp formatted in a different time zone, a random ID, a component that checks window — React reports a hydration mismatch, discards server HTML for part of the page, and re-renders it on the client, costing performance and sometimes visibly flickering.
With React Server Components, the same page is also split into server and client parts, and choosing where those boundaries go determines how much JavaScript ships and how much must hydrate at all.
TL;DR
- Hydration attaches React to server-rendered HTML; the first client render must match the server render.
- Common mismatch causes: dates and locales, random values, browser-only APIs, invalid HTML nesting, user data from localStorage, and browser extensions.
- Render stable output first, then update in
useEffect(or useuseSyncExternalStorewith a server snapshot) for client-only values. - Use
suppressHydrationWarningonly for a single element's text that legitimately differs, such as a timestamp. - Keep
"use client"boundaries small: Server Components render most of the page; client components add interactivity. - Suspense boundaries enable streaming and selective hydration, and contain mismatch recovery to smaller regions.
Quick Example
A component that mismatches because the server and browser format the time differently:
The fix renders a deterministic value on both sides, then refines it after hydration:
A page with a small client boundary — most of it renders on the server and never hydrates:
Core Concepts
What Hydration Does
The server renders components to HTML. The browser downloads JavaScript, React renders the same tree in memory, and instead of creating DOM nodes, it adopts the existing ones and attaches listeners. If text, attributes, or structure differ, React cannot safely adopt them. React reports the difference and client-renders up to the nearest Suspense boundary (or the root), throwing away server HTML for that region.
Common Mismatch Causes
React 19 reports mismatches with a diff of the server and client output, which usually points straight at the cause.
Client-Only Rendering Patterns
useEffectafter mount: render a placeholder or stable value, then update. Simple and correct, at the cost of a second render.useSyncExternalStorewithgetServerSnapshot: subscribe to browser state (online status, media queries) with an explicit server value.- Client-only components: frameworks provide ways to skip server rendering for components that truly cannot render on the server, such as dynamic imports with server rendering disabled.
suppressHydrationWarning: silences the warning for one element's text content one level deep — appropriate for timestamps, not a general fix.
Rendering Boundaries
Props crossing from server to client components must be serializable — plain data, not functions or class instances (Server Actions are the exception). Server components can be passed as children into client components, so a client wrapper does not force its contents to become client code. See React Server Components.
Streaming and Selective Hydration
With Suspense boundaries, the server streams HTML for each section as its data resolves, and React hydrates sections independently — prioritizing the one a user interacts with. A slow widget no longer blocks the whole page from becoming interactive. See React Suspense.
Diagnosing Hydration Problems
- Read the console error and diff; note the component and the differing text or attribute.
- Compare View Source (server HTML) with the live DOM in DevTools.
- Retry in a clean browser profile to rule out extensions.
- Search the component for dates, randomness,
window,localStorage, and conditional rendering. - Validate HTML nesting in the server output.
- Confirm the server and client use the same data, flags, and environment variables.
Best Practices
Make Server and First Client Render Pure Functions of Props
Anything that depends on the browser, the clock, or randomness belongs in effects, subscriptions, or server-provided props.
Push Client Boundaries Down
Mark the smallest interactive components with "use client", not whole pages or layouts, to ship and hydrate less JavaScript.
Wrap Independent Regions in Suspense
Suspense boundaries improve streaming, make hydration selective, and contain the impact of any mismatch to one region.
Test Server Rendering
Add tests or checks that render pages on the server and hydrate them in a browser, failing on hydration warnings in CI.
Common Mistakes
Branching on window During Render
Silencing Instead of Fixing
"use client" at the Top of Every Page
FAQ
What is hydration in React?
The process of attaching React to server-rendered HTML in the browser: React renders the same component tree, adopts the existing DOM nodes, and attaches event handlers so the page becomes interactive.
What causes "Hydration failed because the server rendered HTML didn't match the client"?
The first client render produced different output than the server — usually because of dates or locales, random values, browser-only checks in render, client storage, invalid HTML nesting, or browser extensions.
How do I render something only on the client?
Render a stable placeholder on the server and first client render, then update in useEffect, or use useSyncExternalStore with a server snapshot. Frameworks also offer ways to load specific components only on the client.
Is suppressHydrationWarning safe to use?
For a single element whose text legitimately differs, such as a current timestamp, yes. It does not fix mismatches elsewhere and should not be used to hide structural differences.
How do Server Components reduce hydration costs?
Server Components render only on the server and ship no JavaScript, so they do not hydrate. Only client components below a "use client" boundary hydrate, which reduces JavaScript size and hydration work.
Related Topics
- React — Component model fundamentals
- React Server Components — Server and client component boundaries
- React Suspense — Streaming and selective hydration
- Next.js — A framework built on these patterns
- Next.js Caching and Deployment Diagnostics — Production-only rendering issues
- Web Performance — Faster loading and interactivity