Hydration is the process in which a JavaScript framework running in the browser takes over HTML that was already rendered on the server or at build time, rebuilds its component tree in memory and attaches event handlers and state so the page becomes interactive. In web applications, it connects server-side rendering with the dynamic behavior of a client-side application.
The server-rendered markup lets users see content quickly, while hydration makes that content respond to clicks and input. The gap between the two moments, and the JavaScript cost of closing it, is the central performance question of modern rendering architectures.
How hydration turns static markup into an application
Hydration starts after the browser has parsed the server HTML and downloaded the application bundle. The framework runs the same components that produced the HTML, but instead of creating new DOM nodes it walks the existing DOM and pairs each node with its virtual or reactive counterpart.
- The server renders HTML and embeds serialized data, often as a JSON script block.
- The browser paints the HTML, so content is visible before any JavaScript runs.
- The bundle downloads and executes, recreating component state from the serialized data.
- The framework reconciles its expected output with the existing DOM and attaches listeners.
- The page becomes interactive, and later updates are handled entirely on the client.
The critical assumption is that server and client render identical output for the same data. When they differ, the framework reports a hydration mismatch and either patches the difference or discards the server markup and renders the subtree again, which costs time and can cause visible flicker.
Hydration strategies and their trade-offs
Classic full hydration processes the entire page in one pass, even parts that never change. Newer strategies reduce that cost by hydrating less, later or in smaller pieces.
| Strategy | How it works | Main benefit |
|---|---|---|
| Full hydration | Hydrates the whole component tree at once | Simple model, broad framework support |
| Progressive hydration | Hydrates components over time or on visibility | Shorter main-thread blocks at startup |
| Selective hydration | Hydrates Suspense boundaries independently, prioritizing user input | Interactive regions respond sooner |
| Partial hydration (islands) | Ships JavaScript only for interactive islands | Far less JavaScript on content pages |
| Resumability | Serializes listeners and state so no replay is needed | Near-zero startup execution |
| Server components | Non-interactive components never ship to the client | Smaller bundles and less hydration work |
The right strategy depends on how much of the page is interactive. A dashboard that is interactive almost everywhere gains little from islands, while a content site with a single search box and a menu can avoid most hydration entirely.
Hydration among rendering approaches
Hydration exists only where HTML is produced before the client application runs. It is therefore part of SSR and SSG setups and is absent in pure client-side rendering, where the browser builds the DOM from scratch.
| Approach | Where HTML is produced | Role of hydration |
|---|---|---|
| Client-side rendering | In the browser at runtime | None; the client builds the DOM itself |
| SSR | On the server per request | Required to make the page interactive |
| SSG | At build time | Required for any interactive parts |
| MPA without a framework | On the server | Usually none; small scripts enhance pages |
| SPA with SSR | Server for the first view, client afterward | Runs once, then client routing takes over |
A PWA can use any of these approaches; hydration concerns the first render of a document, while a service worker and caching concern how its resources are delivered.
Performance effects of hydration
Hydration shifts the bottleneck from network and server to the main thread. Server rendering improves FCP and LCP because content arrives in the HTML, but hydration can produce long tasks of hundreds of milliseconds on mid-range phones, which hurts INP and Total Blocking Time.
| Symptom | Likely cause | Remedy |
|---|---|---|
| Clicks ignored after load | Buttons visible before handlers attach | Selective or progressive hydration |
| Long startup tasks | Entire tree hydrated in one pass | Split boundaries, defer offscreen parts |
| Large HTML documents | Data serialized twice, in markup and JSON | Send only data the client needs |
| Flicker after load | Hydration mismatch forces re-render | Make rendering deterministic |
| Slow time to interactive | Big bundles on slow networks | Code splitting, server components |
The period in which a page looks ready but does not respond is sometimes called the uncanny valley of server rendering. It is the most user-visible hydration cost and the main motivation for selective and resumable approaches.
Common causes of hydration mismatches
Mismatches come from non-deterministic rendering: any value that differs between the server run and the client run. Most are avoidable once developers know the usual sources.
- Dates and times formatted with different time zones or locales on server and client.
- Random values such as generated IDs created separately on each side.
- Browser-only APIs like window size or localStorage read during the initial render.
- Invalid HTML nesting, such as a div inside a p, which the parser silently restructures.
- Browser extensions that inject markup before the framework hydrates.
The standard fix is to render a stable placeholder on both sides and apply client-only values in an effect that runs after hydration, so the first client render matches the server output exactly.
The idea in brief
Think of a shop window display that arrives fully arranged, so passers-by can look at it immediately. Hydration is the moment a staff member steps in and connects the display to the till and the lights, so that touching things actually does something.
Before hydration, a web page can look finished but buttons do nothing. After hydration, the page works like a full application. The challenge is making that switch quick and invisible to the visitor.
A practical scenario
An online retailer renders its product pages on the server, and they appear in about 1.5 seconds on a typical phone. Analytics show many shoppers tapping the add to cart button repeatedly, because nothing happens for almost two more seconds while the full page hydrates.
The team profiles startup and finds that reviews, recommendations and the footer are hydrated before the purchase form. They wrap those sections in separate boundaries, hydrate them when they scroll into view and convert the static product description to a server component that ships no JavaScript.
The purchase controls now become interactive within a few hundred milliseconds of first paint. Repeated taps disappear from the analytics, the main-thread startup work shrinks substantially, and the measured INP for the page moves into the good range.