Server-side rendering and hydration are two halves of the same handoff. The server renders a page to real HTML and sends it down on the first request, so the browser has something to paint immediately. Then, once the JavaScript bundle arrives, hydration takes over: it attaches event listeners and internal state to that existing markup instead of throwing it away and rendering the page again from scratch. Understanding where one ends and the other begins explains most of the performance debates in modern frontend frameworks.
What changed in 2026
- React Server Components moved from experimental to default in most new React and Next.js projects, shifting more rendering work to the server and shrinking the amount of markup that needs to hydrate on the client.
- Resumable frameworks gained real production adoption. Qwik and similar approaches skip the hydration step entirely by serializing application state into the HTML itself, so the browser resumes execution instead of replaying it.
- Streaming SSR with Suspense became the default pattern in meta-frameworks, sending markup in chunks as data resolves rather than waiting for the entire page to be ready.
- Partial and selective hydration tooling matured, making it practical to mark only specific components as interactive instead of hydrating an entire route.
How server-side rendering works
On a normal request, the server runs your component code, produces a complete HTML document, and sends it to the browser. The browser can parse and paint that HTML immediately, without waiting for any JavaScript to download or execute. This is why SSR pages tend to have a fast first paint compared with a page that starts blank and renders entirely in the browser.
The tradeoff is that the HTML alone is not interactive. Buttons do not respond, inputs do not update state, and event handlers do not exist yet. That gap is what hydration closes.
How hydration works
Once the JavaScript bundle loads, the framework walks the existing DOM that the server produced and attaches behavior to it: event listeners, component state, and any client-only logic. Crucially, a correct hydration does not re-render the page — it reuses the DOM nodes that already exist, comparing them against what the client-side render would have produced.
This reuse is the entire point. Throwing away the server markup and building fresh DOM nodes would erase most of the benefit of rendering on the server in the first place, and the user would likely see a flash of re-layout.
Why hydration mismatches happen
A hydration mismatch occurs when the markup the client would render does not match what the server sent — different text, a different attribute, or an element that only exists in one environment (a common culprit: code that reads window or formats a date differently on server versus client). The framework then discards the mismatched subtree and renders it again on the client, which is slower and can cause a visible flicker.
The fix is almost always the same: make sure anything the render depends on — locale, time zone, random values, feature flags — resolves identically on the server and the client, or defer that piece of the UI until after hydration.
Rendering and hydration strategies compared
| Approach |
What ships to the client |
Interactivity cost |
| Full hydration |
Entire page's JavaScript, even static parts |
High — everything hydrates, whether it needs to or not |
| Partial hydration (islands) |
JavaScript only for marked interactive components |
Low — static regions never hydrate |
| Resumability (Qwik-style) |
Serialized state; code loads on interaction |
Very low — no replay step at all |
| Client-side rendering only |
Full app bundle, blank HTML shell |
High startup cost, no SSR benefit |
When to reach for SSR
SSR earns its cost on pages where first paint and search visibility matter most — marketing pages, product pages, anything a crawler or an impatient visitor hits cold. It matters less for logged-in, app-like views where the user already has the bundle cached from a previous visit. Content that comes from a headless CMS is a common SSR use case, since the page needs fresh data on every request rather than a stale build.
FAQ
Is hydration always necessary after SSR?
No. Resumable frameworks avoid it by design, and static pages with zero interactivity do not need a JavaScript bundle at all. Hydration is only necessary when the page has client-side behavior that the initial HTML cannot express.
Does SSR slow down the server?
It adds server-side work per request, since the server has to render the page instead of just serving a static file. Caching, streaming, and static generation for pages that do not change per request all reduce that cost.
What causes most hydration mismatch warnings in practice?
Values that differ between server and client: dates formatted with the server's time zone, random IDs generated fresh on each render, or conditional code that checks for window and behaves differently in the browser.
Is SSR the same as static generation?
No. SSR renders on every request; static generation renders once at build time. They solve different problems, and many real sites mix both on different routes.
Where to go next