Qwik's Resumability: Skipping Hydration for Instant Interactivity
Qwik skips hydration by serializing listeners and state into HTML attributes, loading JavaScript chunks only when the user interacts. A concrete counter example shows how to verify lazy loading in DevTools.
06 Apr 2026, 19:52 UTC

The Hydration Tax
Most modern frameworks ship a JavaScript bundle that must download, parse, and execute before any button click works. On mobile or low-end devices this "hydration" phase can take seconds, leaving users staring at a frozen UI. Qwik takes a different bet: serialize everything the browser needs into the initial HTML so interactivity resumes the moment the page appears.
How Resumability Works
Instead of re-executing component logic on the client, Qwik compiles each component into fine-grained chunks marked with a $ suffix. Event listeners and component state are serialized as HTML attributes—essentially JSON embedded in the markup. When a user clicks, the framework lazy-loads only the chunk that handles that interaction, applies the stored state, and runs the handler. No full component tree walk, no virtual DOM reconciliation, no hydration.
Worked Example: A Counter That Loads on Click
Create a fresh Qwik City project:
npm create qwik@latest my-app
cd my-app
npm installAdd a counter component in src/components/counter.tsx:
import { component$, useStore } from '@builder.io/qwik';
export const Counter = component$(() => {
const count = useStore({ value: 0 });
return (
count.value++}>
Count: {count.value}
);
});Import it in a route (src/routes/index.tsx) and run npm run start. View the page source—you'll see something like:
<div on:click="./chunks/counter.abc123.js" q:obj="count:0">Count: 0</div>The on:click attribute points to a lazy-loaded chunk; q:obj holds the serialized state. Open Chrome DevTools → Network tab, enable "Disable cache", reload, then click the counter. A tiny chunk (counter.abc123.js) loads only after the click. Console shows no hydration warnings.
Trade-offs and Limits
- HTML bloat: Large component trees serialize many listeners and state objects into attributes, increasing initial payload size.
- Learning the $ syntax: Event handlers must use
onClick$,onSubmit$, etc. Accidental closures over non-serializable values prevent chunk extraction. - Server dependency: Resumability assumes the server sends fully rendered HTML. If the initial HTML is missing or corrupted, Qwik cannot recover state and may fall back to full hydration.
Quick Verification Checklist
- Run
npm create qwik@latestand add the counter component above. - Start the dev server and open the page source—confirm
on:clickandq:objattributes exist. - In DevTools Network tab, reload with cache disabled, click the counter, and verify a single chunk loads on demand.
- Check console for hydration warnings; there should be none.
When to Adopt
If your pages are content-heavy with sporadic interactivity—marketing sites, docs, e-commerce product pages—Qwik's resumability can shave seconds off time-to-interactive. For highly interactive apps where most components are active immediately, the HTML overhead may outweigh the benefit. Start by converting a single static route to Qwik City, measure the chunk sizes, and decide from real data.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.