Time and randomness
Dates, counters, UUIDs, random ordering, and expiring state differ across executions.
Quick reference · Print-friendly
Trace identity first, then scheduling, then payload cost.
| Stage | What exists | What can fail | Evidence |
|---|---|---|---|
| Server render | HTML snapshot + serialized inputs | Nondeterminism, leaked personalization, slow data | Response HTML, server spans, TTFB |
| Browser paint | DOM and native browser behavior | Layout shift, misleading controls, blocked resources | Filmstrip, LCP, resource waterfall |
| Code startup | Downloaded and evaluated modules | Large bundles, long tasks, dependency waterfalls | Coverage, CPU profile, TBT/INP |
| Hydration | Client tree matched to existing DOM | Mismatch, stale snapshot, boundary suspension | Recoverable errors, component stack, traces |
| Interactive | Managed state, events, effects, subscriptions | Queued intent, lost clicks, slow updates | Interaction traces, field INP, task success |
Dates, counters, UUIDs, random ordering, and expiring state differ across executions.
Rendering on window, storage, viewport, media queries, or feature detection changes the tree.
The client reads fresher data instead of hydrating from the serialized server snapshot.
Invalid nesting causes the browser parser to repair HTML before the runtime matches it.
Formatting depends on defaults that are not identical across server and browser.
Extensions, scripts, personalization, or A/B tools modify nodes before hydration.
onRecoverableError.“Visible is not equivalent to interactive; I would inspect the gap between paint, code availability, and boundary hydration.”
“The client should hydrate from the server snapshot, then converge on fresher state.”
“Streaming and selective hydration share Suspense boundaries, but one schedules HTML delivery and the other schedules client activation.”
“Boundary placement should follow independent user intent, latency, and failure—not the component-file tree.”