Stopping the Hydration Tax: Implementing Resumability with Qwik
Stop paying the 'hydration tax.' Learn how Qwik's resumability eliminates the need to re-execute JavaScript on the client, drastically reducing Time to Interactive.
28 Feb 2026, 11:10 UTC

The Hydration Bottleneck
Most modern web frameworks follow a pattern called hydration. The server renders HTML to show the user content quickly, but the browser must then download all the component JavaScript, execute it, and rebuild the internal state tree to make the page interactive. This "hydration tax" creates a gap where the page looks ready, but clicking a button does nothing—increasing Total Blocking Time (TBT) and delaying Time to Interactive (TTI).
Qwik solves this by replacing hydration with Resumability. Instead of re-executing the application logic on the client, Qwik serializes the application state and event listeners directly into the HTML. The browser doesn't "boot up" the app; it simply resumes it from where the server left off.
How Resumability Works in Practice
To achieve this, Qwik uses a specialized optimizer during the build process. It breaks your components into tiny, independent chunks. When you write a click handler, Qwik doesn't bundle that function into the initial JS payload. Instead, it adds a attribute to the HTML element that points to the specific JS chunk needed for that interaction.
The Role of Signals
Resumability relies on Signals—reactive state primitives that track where they are used. Because signals are serializable, Qwik can write the current value of a piece of state into the HTML. When a user interacts with a signal-linked element, Qwik only downloads the code necessary to update that specific signal and the DOM elements that depend on it, rather than re-rendering a whole component tree.
Example: Implementing a Resumable Counter
In a traditional framework, a counter requires the entire component logic to be loaded before the button works. In Qwik, the logic is deferred until the click occurs.
import { component$, useSignal } from '@builder.io/qwik';
export default component$(() => {
const count = useSignal(0);
return (
<div>
<p>Count: {count.value}</p>
<button onClick$={() => count.value++}>
Increment
</button>
</div>
);
});
Technical Breakdown of the Example
- The $ Suffix: Notice
component$andonClick$. The$tells the Qwik optimizer to split this function into a separate lazy-loadable chunk. - Execution Flow: When the page loads, 0 bytes of JS for the counter are executed. Only when the user clicks the button does the browser fetch the small JS chunk containing the
count.value++logic. - Permissions: This code runs in a standard Qwik project environment. No special server permissions are required beyond standard Node.js/Edge runtime access for SSR.
Trade-offs and Limitations
Resumability is not a magic bullet; it shifts the complexity from the client to the build step and the server.
| Consideration | Impact |
|---|---|
| Server Dependency | Since the state is serialized on the server, initial page delivery is heavily dependent on SSR latency. |
| Optimizer Constraints | Standard JS patterns that aren't wrapped in $ markers may not be optimizable, potentially leading to larger bundles if not used correctly. |
| Mental Model | Moving from hooks (like React's useState) to signals requires a shift in how you think about state propagation. |
Verifying the Result
To confirm that your application is actually resumable and not hydrating, perform these three checks:
- Inspect the DOM: Open Browser DevTools and look at your HTML elements. You should see
q-attror similar attributes containing serialized state and event handler references. - Monitor the Network Tab: Refresh the page. You should see almost no JavaScript loaded initially. Click an interactive element; you should see a small
.jschunk load exactly at the moment of interaction. - Measure TBT: Run a Lighthouse report. Compare the Total Blocking Time of a Qwik page against a traditional hydrated page of similar complexity. The Qwik page should show significantly lower TBT.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.