Hydration vs Resumability: Two Ways to Go Interactive
Hydration re-runs a framework's JS to attach interactivity after render; resumability serializes state so the browser can skip that work.
Hydration is the process of re-running a framework’s JavaScript on the client to attach event listeners and rebuild component state after the server has already sent rendered HTML. Resumability is a different strategy that avoids that re-execution entirely, by serializing enough state into the HTML that the browser can pick up exactly where the server left off, only running the JavaScript for a component when it’s actually interacted with. Both aim to solve the same problem — making server-rendered HTML interactive without a blank-page wait — but they get there by fundamentally different means.
What hydration does, and why it’s expensive
Server-side rendering sends the browser a fully formed page of HTML, so content is visible immediately — no waiting on JavaScript to paint anything, which is a major factor behind a good critical rendering path. But that HTML is inert. Buttons don’t respond to clicks, forms don’t validate, and nothing in the page has state yet, because none of the framework’s JavaScript has run on the client.
Hydration fixes this by downloading the same component code that rendered the page on the server, and running it again in the browser — walking the DOM that already exists, reconstructing each component’s internal state, and attaching the event listeners that make the page respond to input. The critical cost is that this work scales with the entire page, not with what the user is actually about to interact with: a component the user will never touch still gets fully re-executed and re-attached during hydration, because the framework has no way of knowing in advance which parts of the page matter.
This is why hydration-heavy pages can look done and still feel sluggish — the HTML is painted, but the JavaScript-driven “time to interactive” lags behind it while the framework works through the whole component tree. React Server Components and island architectures both emerged largely as answers to this cost, by shrinking how much of the page needs to hydrate at all rather than changing what hydration itself does.
What resumability does differently
Resumability takes a more radical position: instead of trying to reduce how much hydration happens, it tries to eliminate the need to re-run component logic on the client at all. The server doesn’t just render HTML — it also serializes the application’s state and the listeners that were attached during server rendering directly into the page, in a form the browser can read without executing any framework code.
When the user actually interacts with something — clicking a button, say — the browser downloads and runs only the specific, small chunk of JavaScript needed to handle that one interaction, using the state that was already serialized rather than reconstructing it from scratch. Nothing “hydrates” up front, because there’s no bulk re-execution step to skip past in the first place; the page simply resumes exactly where the server left off, one interaction at a time, as those interactions actually occur.
The trade-off is architectural, not just an optimization flag: resumability requires a framework built around fine-grained serialization from the ground up, since it depends on being able to capture and reconstruct precise pieces of state and closures across the server-client boundary. It isn’t something you retrofit onto a framework designed for hydration.
Hydration vs resumability
| Hydration | Resumability | |
|---|---|---|
| Client work before interactivity | Re-executes and re-attaches the whole hydrated tree | None — resumes from serialized state |
| JS downloaded upfront | Proportional to the hydrated component tree | Minimal — code loads per interaction |
| Time to interactive | Scales with page size | Scales with what the user actually touches |
| Framework requirement | Works with conventional component models | Requires fine-grained state serialization by design |
| Mitigation strategies | Partial/island hydration, lazy hydration | Not needed — the model avoids the cost outright |
Partial hydration as a middle ground
Between full-page hydration and true resumability sits partial hydration, most visibly popularized by island architectures: most of the page stays static HTML, and only specific, marked components — a search box, a cart widget — ship JavaScript and hydrate independently. This doesn’t eliminate hydration’s per-component cost, but it shrinks the scope dramatically, since the framework only has to re-execute and reconstruct state for the islands that were actually marked interactive, not the whole page.
It’s a pragmatic compromise: it keeps the conventional hydration model, which most frameworks and their ecosystems are built around, while addressing the worst of the “hydrating things nobody will touch” problem that makes naive full-page hydration slow. Signals-based state management has also made incremental hydration more efficient, since fine-grained reactivity means updating one piece of state doesn’t require re-running a broader component tree the way coarser virtual DOM diffing can.
Which approach fits which project
Resumability’s benefit is largest on content-heavy pages with a lot of markup but comparatively little interactivity — the kind of page where a conventional framework would hydrate a large tree just to handle a handful of possible clicks. Conventional hydration, especially combined with islands or lazy hydration, remains the more battle-tested and broadly supported approach, with a larger ecosystem and fewer architectural constraints on how state and logic are structured. Static rendering strategies more broadly — see SSR vs SSG — interact with both approaches the same way: the rendering strategy decides what HTML the server sends, while hydration or resumability decides how that HTML becomes interactive afterward.
The takeaway
Hydration makes server-rendered HTML interactive by re-running the same component code on the client, at a cost that scales with the whole hydrated tree regardless of what the user actually uses. Resumability sidesteps that cost by serializing state into the page and only executing JavaScript for the specific interaction a user triggers, but it requires a framework designed around that model from the start. Partial hydration through islands is the pragmatic middle ground most teams reach for today — full resumability is a bigger architectural commitment, best justified by pages where the gap between “rendered” and “interactive” is large enough to actually matter.
Tagged
Keep reading
Takina · · 4 min read Web Locks API: Coordinating Work Across Browser Tabs
The Web Locks API lets JavaScript acquire named locks shared across tabs, so only one tab does work like a token refresh or a write at a time.
Takina · · 4 min read Svelte 5 Runes Explained
Svelte 5 runes like $state and $derived replace the old reactive-assignment magic with explicit function calls that work anywhere in a file.
Takina · · 4 min read Shallow Copy vs Deep Copy in JavaScript
A shallow copy duplicates an object's top-level properties but shares nested references; a deep copy duplicates everything recursively. How to do each.