Resumability vs Hydration: What Changes for Startup and INP

This comparison extends Hydration & Partial Rehydration Strategies within JavaScript Bundle Optimization & Code Splitting. Hydration — in all its variants — rebuilds application state on the client by re-executing component code: the server renders HTML, then the client downloads the same components, runs them again, and attaches event listeners. Partial hydration and islands reduce how much is re-executed; they do not remove the re-execution itself.

Resumability, popularised by Qwik, takes a different approach. The server serialises the application state and the location of event handlers into the HTML. The client starts with a tiny global loader that listens for events; when the user interacts, it fetches only the code for that specific handler and resumes from the serialised state, without re-running components. Startup JavaScript becomes nearly constant regardless of page complexity; the cost moves to the first interaction with each feature.

Hydration vs resumability at startup Comparison of what the browser does at startup under hydration and under resumability. Hydration vs resumability at startup Hydration • Download component code for the page • Re-execute components to rebuild state • Attach listeners after hydration • Startup cost grows with page complexity Resumability • Download a ~1KB event loader • State read from serialised HTML • Handler code fetched on first use • Startup cost roughly constant

Rapid Diagnosis: Is Hydration Your Bottleneck?

  • Measure hydration time on your heaviest templates in a throttled trace. If it dominates TBT and early-interaction input delay, the architecture matters.
  • Count interactive regions. Pages with many interactive widgets spread across the page benefit most from lazy, per-handler loading.
  • Check what partial hydration already gives you. If islands or server components already cut startup JS to a small fraction, resumability's marginal gain shrinks.
  • Check interaction patterns. If users interact immediately and with many features, per-interaction code loading may make first interactions slower.

Root Cause Analysis: Where Each Model Pays

1. Hydration pays at startup. Code for every hydrated component downloads and executes before it is interactive, competing with LCP resources and creating long tasks.

2. Resumability pays at first interaction. The first click on a feature may need a network request for its handler chunk before it runs, adding latency to that interaction unless code is prefetched.

3. Serialisation has a size cost. Resumable HTML carries serialised state; large state inflates HTML, which affects TTFB transfer and parse.

4. Ecosystem and mental model. Resumable frameworks constrain how closures and state are written so they can be serialised; existing React or Vue component libraries do not resume.

Startup and first click under each model (mid-tier phone) Two timelines comparing startup work and the first interaction under hydration and resumability, showing where each pays its cost. Startup and first click under each model (mid-tier phone) Hydration HTML paint hydrate page Resumable HTML paint 0ms 400ms 800ms 1200ms 1600ms 2000ms 2400ms Hydration front-loads ~800ms of work; resumability defers a smaller cost to the first click, which prefetching can largely hide.

Step-by-Step: Evaluating the Trade-Off

1. Quantify hydration cost on your real pages

javascript
// Mark hydration boundaries to measure them in the field.
performance.mark('hydrate:start');
hydrateRoot(document.getElementById('root'), <App />);
requestAnimationFrame(() => performance.measure('hydrate', 'hydrate:start'));
// trade-off: this measures from the hydrate call to the next frame, which
// includes rendering; for React 18 concurrent hydration the work may be split
// across several tasks — measure the total, not the first task.

Expected outcome: a p75 hydration time per template on real devices.

2. Model first-interaction latency under resumability

Estimate handler chunk sizes and the network time to fetch them on your users' connections. Resumable frameworks prefetch likely handlers in the background (Qwik uses speculative module prefetching via a service worker), so the realistic first-interaction cost is often small — but measure it with a prototype rather than assuming.

3. Compare against partial hydration alternatives

Before rewriting, try the hydration-reducing options in your current stack: server components, islands, lazy hydration of below-the-fold components, and selective hydration. Many of the gains are available without a framework change.

4. Prototype the heaviest template

Build one representative page in the resumable framework and compare startup JS, TBT, LCP and first-interaction INP under the same throttling.

Choosing an approach by page type Suitability of full hydration, islands or server components, and resumability for different kinds of pages. Choosing an approach by page type Page type Full hydration Islands / RSC Resumability Content site wasteful excellent excellent E-commerce product page heavy good very good App-like dashboard acceptable limited gains gains smaller Existing large React app status quo incremental path rewrite needed

Verification

For a prototype, compare under identical conditions: startup JavaScript bytes, main-thread time before interactive, LCP, and INP for the first interaction with each major feature. Resumability should show dramatically lower startup cost; check that first-interaction INP stays under 200ms with prefetching enabled. For production, monitor INP split by "first interaction with feature" versus later interactions.

Worked Example: A Product Listing Prototype

A team prototyped their product listing page — filters, sort, quick-view modals, add-to-cart — in a resumable framework. Compared with the existing React page (already code-split), startup JavaScript fell from 180KB to 6KB, lab TBT from 520ms to 40ms, and LCP improved by 300ms. First-click latency on filters, measured cold on a throttled profile, rose from 60ms to 210ms without prefetching and fell to 80ms with speculative prefetching enabled. The team concluded resumability was compelling for new storefront pages, but adopted React Server Components for the existing app, which captured roughly 60% of the startup gain without a rewrite.

Common Mistakes

  • Comparing against an unoptimised hydration baseline. Measure against your best partial-hydration option, not the worst.
  • Ignoring first-interaction latency. Startup wins can be offset by slow first clicks without prefetching.
  • Assuming component libraries carry over. Most existing UI libraries need replacement or wrappers.
  • Serialising huge state. Resumable HTML can bloat if large datasets are serialised; keep state minimal.

Edge Cases

Offline and flaky networks. Lazy handler fetching depends on the network at interaction time; service-worker prefetching mitigates this, but truly offline use needs precaching.

Third-party scripts. Resumability does nothing for third-party JavaScript, which may still dominate startup.

Mixed architectures. Some frameworks embed React islands within resumable pages; those islands hydrate normally, reintroducing hydration cost for that part.

Analytics on early interactions. Event delegation through a global loader changes how and when events reach your code; verify analytics still capture interactions correctly.

What Resumability Teaches Even If You Never Adopt It

The resumable model is a useful lens for any framework. It asks, for each piece of client JavaScript: does this need to run before the user does anything? Most code on a typical page does not — it exists to respond to interactions that may never happen. Applying that question in a hydration-based app leads to the same practical moves: render static content on the server without client code, load interaction handlers lazily (on hover or first use), keep startup code to what the first paint and the first likely interaction require, and serialise state into the HTML instead of refetching it on the client. Teams that internalise this tend to ship much smaller startup bundles whatever framework they use.

FAQ

Is resumability the same as islands?

No. Islands hydrate selected components fully when triggered; resumability never re-executes components to rebuild state, and loads code at the granularity of individual handlers. Both reduce startup cost; resumability goes further at the price of a different programming model.

Does resumability help INP after startup?

Mostly through reduced startup contention. Once code is loaded, interaction cost depends on what your handlers do, as in any framework. The main INP benefit is fewer long tasks during load, when many first interactions happen.

What about React's server components plus selective hydration?

They capture much of the benefit for React apps: less client code and prioritised hydration of interacted regions. They still hydrate client components, so startup cost scales with the interactive surface rather than staying constant.

Is the serialised state a security concern?

It is visible in the HTML like any server-rendered data. Do not serialise secrets or data the user should not see; the same rule applies to any framework's hydration payload.

How mature is the ecosystem?

Resumable frameworks are production-ready for many use cases but have smaller ecosystems than React or Vue. Factor in hiring, component availability and long-term maintenance, not just performance numbers.