SSR and hydration
Understand server-rendered HTML, client hydration, mismatch causes, and the boundary between server and client work.

WHAT YOU WILL BE ABLE TO DO
Learning outcomes
- Explain ssr and hydration in plain language.
- Connect the behavior to the underlying browser or framework model.
- Implement the core pattern and reason through edge cases.
- Answer common follow-ups without relying on memorized phrases.
01Explain it simply
Server-side rendering produces HTML before JavaScript reaches the browser. Hydration then attaches React's event handling and component state to that existing markup rather than recreating it from nothing.
One-line definition: Understand server-rendered HTML, client hydration, mismatch causes, and the boundary between server and client work.
02Mental model
The first client render must describe the same tree the server emitted. Time, randomness, browser-only APIs, locale differences, and invalid HTML can make those trees disagree.
03Step by step
- Render deterministic content on server and first client pass.
- Move browser-only reads into an effect or client-only boundary.
- Serialize server data safely.
- Stream independent boundaries when supported.
- Measure both server response time and hydration/main-thread cost.
04Working example
function Clock() { const [time, setTime] = useState<string | null>(null); useEffect(() => { setTime(new Date().toLocaleTimeString()); }, []); return <time>{time ?? 'Loading time…'}</time>;}The server and first client render agree on the placeholder. The browser-specific localized time appears only after hydration, preventing a mismatch.
05Where it is used
- Content-heavy landing pages
- Search and social previews
- Faster usable HTML on slow devices
- Streaming data boundaries
06Common mistakes
- Reading window during server rendering
- Rendering Date.now or Math.random directly
- Assuming SSR removes the cost of client JavaScript
- Suppressing hydration warnings instead of fixing the cause
07Interview answer
Separate HTML generation, network delivery, hydration, and later client renders. Explain both the performance benefit and the JavaScript cost.
Why can new Date().toLocaleString() cause a hydration mismatch?
The server and browser can render at different times and with different locales or time zones, producing different text for the same initial tree.
DDConcept deep dives
Deep dive 1
Server rendering produces an initial representation
The server renders components to HTML so the browser can display and index content before client JavaScript finishes. That improves delivery but does not make interactive components functional by itself. Hydration runs the client tree against that HTML, attaches React behavior, and reuses matching DOM rather than blindly recreating the page.
- Server response time, HTML streaming, resource discovery, and client hydration are separate performance stages.
- A large client bundle can erase the interaction benefit of early HTML.
- Server Components can keep selected rendering logic and dependencies out of the client graph.
Deep dive 2
The first client tree must be deterministic
Hydration expects the client render to describe the same content the server emitted. Time, randomness, environment defaults, browser-only APIs, invalid nesting reparsed by the browser, and data races all create mismatches. Resolve stable inputs on the server or render a shared placeholder; suppressHydrationWarning is a narrow escape hatch, not a repair strategy.
- Pass locale and time zone explicitly when formatting initial text.
- Read localStorage or viewport state after hydration unless a consistent server snapshot exists.
- Validate the final browser DOM when invalid HTML may be reparsed.
Deep dive 3
Streaming reveals independent boundaries
A server can stream an initial shell and later send content for completed Suspense boundaries. This reduces the need to wait for the slowest dependency before delivering useful HTML. Boundaries should reflect meaningful reveal groups, reserve layout space, and pair with error recovery. Progressive hydration can prioritize interaction without hydrating the whole tree as one blocking operation.
- Do not wrap every small fragment in a spinner-producing boundary.
- Keep navigation and essential controls outside slow content boundaries.
- Measure both network progress and main-thread hydration on realistic devices.
QAInterview questions and model answers
Attempt each answer aloud before opening it. The model answer shows the depth and precision expected in an interview; it is not a script to memorize.
Intermediate · Conceptual · 1 min · Question 1What is hydration?Open model answer
Model answer
Hydration is React attaching behavior to server-rendered HTML by rendering a matching client tree and connecting event handling and component state. It reuses existing DOM when the initial output agrees; it is not simply downloading HTML.
Open question page →Intermediate · Coding · 1 min · Question 2What causes hydration mismatches?Open model answer
Model answer
Nondeterministic output such as time or randomness, different locale or time zone, invalid HTML reparsing, browser-only branches, extensions, and data differences can make server and first-client trees disagree. The fix is deterministic initial rendering, not blanket suppression.
// Mismatch: server and client compute different text<span>{new Date().toLocaleTimeString()}</span>
// Fix: render a stable value, then update after mountconst [now, setNow] = useState(null);useEffect(() => setNow(new Date()), []);Intermediate · Conceptual · 1 min · Question 3Does SSR eliminate client JavaScript cost?Open model answer
Model answer
No. SSR can deliver visible and meaningful HTML earlier, but interactive client components still require downloading, parsing, executing, and hydrating JavaScript. Server components or progressive enhancement can reduce what must reach the client.
Open question page →Intermediate · Conceptual · 1 min · Question 4How do streaming and Suspense interact with SSR?Open model answer
Model answer
The server can stream an initial shell and later reveal completed Suspense boundaries. This improves progressive delivery, but boundary placement must avoid disruptive layout shifts and still provide meaningful fallbacks and error handling.
Open question page →Intermediate · Conceptual · 1 min · Question 5Where should browser-only APIs be read?Open model answer
Model answer
Use them in client-only event handlers, effects, or deliberately isolated client boundaries. If their values affect initial UI, provide a deterministic server-compatible snapshot or render a stable placeholder until after hydration.
Open question page →Advanced · Conceptual · 1 min · Question 6What is selective hydration?Open model answer
Model answer
React can prioritize hydrating parts of a streamed interface based on readiness and user interaction instead of treating the whole page as one blocking unit. This improves responsiveness but does not excuse shipping excessive client code.
Open question page →Advanced · Conceptual · 1 min · Question 7What does suppressHydrationWarning do?Open model answer
Model answer
It suppresses warnings for a limited element-level mismatch and is intentionally shallow. It should be reserved for unavoidable content differences, not broad tree errors.
Open question page →Advanced · Conceptual · 1 min · Question 8Can event handlers run before their region hydrates?Open model answer
Model answer
React can prioritize hydration in response to interaction and replay supported events, but shipped JavaScript and boundary readiness still determine when behavior becomes available.
Open question page →Advanced · Conceptual · 1 min · Question 9Why can invalid nested HTML cause hydration failure?Open model answer
Model answer
The browser parser repairs invalid markup into a DOM different from the server's serialized structure, so React's expected tree no longer matches the actual nodes.
Open question page →Advanced · Conceptual · 1 min · Question 10What should be measured for SSR performance?Open model answer
Model answer
Measure server response, streaming milestones, LCP resource discovery, transferred and executed JavaScript, hydration cost, and interaction latency rather than first HTML alone.
Open question page →SCScenario questions
Scenario 1
A price displays differently on the server and client because each uses the environment's default locale.
- Make locale and currency explicit request data.
- Use the same serialized inputs for server and first client render.
- Avoid formatting from ambient machine defaults.
- Test multiple locales and time zones in production mode.
Reveal worked answer
The initial render must be deterministic. I would resolve locale and currency on the server, serialize them with the data, and format using those explicit values on both sides. If client-specific preference is only available later, render a stable initial representation and update after hydration.