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

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

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

  1. Read the console error and diff; note the component and the differing text or attribute.
  2. Compare View Source (server HTML) with the live DOM in DevTools.
  3. Retry in a clean browser profile to rule out extensions.
  4. Search the component for dates, randomness, window, localStorage, and conditional rendering.
  5. Validate HTML nesting in the server output.
  6. 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

References