Hydration attaches client behavior to HTML that the server has already produced. Its first comparison is a correctness boundary: the initial client tree must describe the same content and structure as the server output. A date formatted in different time zones, a random identifier, or a browser-only preference read during render can break that agreement. Decide which values are part of the request snapshot, serialize them safely, and render them unchanged for the first client pass. Browser-only preferences can update after hydration, with a reserved space or stable placeholder where a change would otherwise shift the page.
Hydration and Deterministic First Render
Working case
The review queue server renders case 47 as 'Pending' and a timestamp in its configured time zone. A reviewer opens the page in another time zone; the browser reformats the timestamp before hydration completes. The client now expects a different text node. Keep the first timestamp as a stable machine value and display format agreed by both sides, then change to the reviewer's locale after mount if the product requires it. The case status is more serious: it must come from the same server snapshot, not a stale browser cache read during the initial render.
Implementation boundary
function firstRenderCase(snapshot) {
return { caseId: snapshot.caseId, status: snapshot.status, updatedAt: snapshot.updatedAt };
}
const serverSnapshot = { caseId: 47, status: "Pending", updatedAt: "2026-10-04T08:12:00Z" };
console.log(JSON.stringify(firstRenderCase(serverSnapshot)) === JSON.stringify(firstRenderCase(serverSnapshot)));
// Output: trueThe small function makes the intended invariant visible: both environments receive the same serialized snapshot. In a real component, avoid reading localStorage, window size, or a current clock value during the first render. A post-hydration effect may read those values and update presentation. Keep user-specific HTML behind the right authentication and cache policy; deterministic output is not permission to serve one person's snapshot to another. Test rendered HTML and hydrated DOM with the same input, then repeat under another locale and time zone.
Cost and boundaries
Server rendering adds work and bytes on the server, while hydration still loads client JavaScript for interactive regions. For n rendered case rows, creating the first tree is O(n) in the number of rows and carries corresponding DOM memory; reformatting every row after mount adds another O(n) pass. A small, stable first view may feel faster than an empty shell, but duplicate work and large serialized snapshots can erase the benefit. Measure first content, interaction readiness, and mismatch logs together rather than relying on a single loading metric.
Failure trace
A developer replaces the initial status with a value from localStorage to make navigation appear instant. On a cold entry the server shows Pending, while the client reads Resolved from a previous session. Hydration reports a mismatch, and the visible label may flicker. Another developer suppresses the warning without resolving the conflicting source of truth. Preserve the server snapshot for the first pass, then fetch or reconcile current data explicitly; a warning suppression should be limited to a genuinely unavoidable text difference, not used to hide a broken data contract.
Verification
- Server HTML and first client tree agree across time zones.
- A stale local preference cannot alter the initial record status.
- A second account never receives another reviewer's serialized case.
Practice drill
Render case 47 in two time zones and with two stored preference values. Capture server HTML before scripts and the first client tree, then compare status, timestamp, and element order. Simulate a stale stored status and verify the first render still follows the request snapshot. After hydration, apply the local preference and observe whether layout shifts. Finally test a second account on a shared cache path; its HTML must never contain case 47 unless that account is allowed to see it.
Decision note
Treat the server response as the exact first-render snapshot and move browser-only reads to a later, owned update.
Common Mistakes
- Calling a clock or random generator in initial render.
- Reading browser storage before hydration for visible server content.
- Silencing a mismatch while its data sources still disagree.
Connected lessons
Server Rendering and Client Data Flow; Server Data Bootstrap and Freshness; Client Cache Keys and Invalidation; Optimistic Mutations and Rollback; Static, Server-Rendered, and Client-Rendered Pages; React Effects and Request Races; Untrusted output: escape by context and constrain scripts.
Apply and check
Build Project: server-rendered case queue and review Web Development: rendering and forms decisions quiz.
