Skip to content

Hydration and its cost

Visible HTML and working client behavior are separate milestones.

Predict first

Before you read: predict

A console page is delivered with a visible button and an application click handler supplied by a client component. A proctor clicks once before the client root is started, then the harness starts the matching root and waits for its readiness signal before a second click.

What cumulative application-handler counts does the fixture observe?

Pick one

The 30-second version

Server HTML can show a component before client behavior is attached. Hydration runs the client tree against that snapshot and connects logic. Work depends on the hydrated tree and its code. Initial output must match the server snapshot; a mismatch can require recovery. A boundary can become ready; early clicks before root setup are not replayed.

Visible HTML and working client behavior are separate milestones.

How it works

Step 1 of 8

Snapshot. Server HTML records initial output, not an executable client handler closure. React

Analogy: A restored pipe organ

A restored pipe organ can have a polished facade and finished keys while the builder reconnects the mechanisms between keys and pipes. A visitor sees an instrument before every intended action is connected. Connecting additional stops adds work even when the facade looks unchanged. The comparison is between visible presentation and connected behavior.

Organ restoration Hydration
Finished facade Visible server snapshot
Reconnecting key mechanisms Attaching client behavior
More stops requiring work A larger hydrated tree
Facade and mechanism disagree Inconsistent server/client output

The organ does not model event replay. Render versus commit belongs to react-render-commit; Server Component bundle boundaries belong to next-server-client-components; interaction latency belongs to perf-inp.

Examples, run for real

4.1 EXH-1600: appearance and activation are separate observations

The local page receives HTML from React's server renderer. Its harness controls when the matching client root begins and records application-handler activity around a pre-start and post-ready interaction. A plain link or native form may still have browser behavior independently of a client handler. A separate local control deliberately installs both the hydrated handler and an extra native listener; the asserted output is [2,4] after two clicks, showing that duplicated attachment changes application counts. A companion control starts with server HTML, waits for a client promise, and records a persistent focus event after release. hydrateRoot

MR !1800 keeps unrelated console widgets outside the owned client fragment. The fixture separates an interaction before root setup from a persistent event delivered to an already established, blocked boundary.

4.2 Catalog work without a stopwatch claim

The count fixture renders several catalog tree shapes with the same Row component and production React without StrictMode. Its independent worked tree contains three Rows and records worked_tree: 3. It also retains ordinary static spans next to a smaller owned island. The island itself includes two nested static children, so the observation distinguishes the selected client tree from nearby server-only HTML. A product page can therefore retain explanatory markup while hydrating only the control that needs behavior. This isolates ownership scope from network transfer, retry behavior and a claim about wall-clock time. Rendering on the web

The exercise does not rely on the bare statement that Server Components can ship no client JavaScript. It compares local client ownership scopes and the observed counts in the same document.

4.3 Replay and recovery are separate cases

The replay fixture begins with a completed server boundary. The client boundary waits on a harness-controlled promise while the root is already established; the fixture records the event log before and after release. A separate fixture compares a matching first render with two kinds of initial disagreement: changed text and a changed element kind. It records final content, node identity and recoverable-error presence. Selective hydration, hydration guidance

These examples are narrow. They do not promise attribute patching, universal replay, or a wall-clock cost.

Try it

Answer first, then check. Nothing is saved.

Question 1 of 5

A server button begins with one label, while the first client render supplies a different label. No warning suppression is used.

Which result does the fixture observe?

Pick one

Question 2 of 5

A client root already exists around server HTML. A completed boundary waits for a local readiness promise. The existing control receives focus before that promise is released.

What does the fixture record after release?

Pick one

Question 3 of 5

A root contains one owned Button island with two nested static children and seven static sibling Rows. The fixture retains all static markup.

If the owned island alone is hydrated, how many client component calls does it observe?

Pick one

Question 4 of 5

Server HTML is <span id="control">Ready</span>. A candidate client tree first returns that matching span, then an effect returns <button id="control">Client</button>.

Which tuple does the fixture record: final text, original-node identity, recoverable error?

Pick one

Question 5 of 5

A bootstrap helper calls root.render while a server-rendered boundary is still waiting on its client promise.

Which final pair does the fixture observe?

Pick one

Go deeper

Pro tip

Keep the server snapshot and first client inputs together in a hydration bug report so a teammate can reproduce the same disagreement.

Sources

Fetched 2026-09-30 through the saved source transport: React hydrateRoot and React working group: Selective Hydration. P2 is executed-only because the saved official React reference does not key the narrower replay rule.

Checked against the tools and docs as of 2026-09-30.