React hydrates the entire page on load. Qwik resumes exactly where the server left off — zero hydration cost, instant interactivity.
What is Qwik?
Qwik is a web framework that achieves instant-loading web applications by eliminating hydration. Instead of replaying the app's initialization in the browser, Qwik serializes the application state on the server and resumes it lazily in the browser.
Why Qwik Is Fundamentally Different
1. Resumability (Not Hydration)
Traditional frameworks (React, Vue, Angular):
Server renders HTML → Browser downloads JS → Browser re-executes (hydrates) → Interactive
Qwik:
Server renders HTML → Interactive (JS loads only when needed)
2. Lazy Loading by Default
import { component$, useSignal } from '@builder.io/qwik';
export const Counter = component$(() => {
const count = useSignal(0);
return (
<button onClick$={() => count.value++}>
Count: {count.value}
</button>
);
});
The $ suffix tells Qwik to lazy-load the click handler. It only downloads when the user actually clicks.
3. Near-Zero JavaScript on Load
Page load comparison (e-commerce homepage):
React: 450KB JS, 3.2s TTI
Next.js: 280KB JS, 2.1s TTI
Qwik: 1KB JS, 0.3s TTI
Qwik ships ~1KB of JavaScript on page load regardless of application size.
4. Familiar Syntax
import { component$, useStore, useTask$ } from '@builder.io/qwik';
export const TodoApp = component$(() => {
const state = useStore({
todos: [] as string[],
input: '',
});
useTask$(({ track }) => {
track(() => state.todos.length);
console.log(`Now have ${state.todos.length} todos`);
});
return (
<div>
<input
value={state.input}
onInput$={(e) => (state.input = (e.target as HTMLInputElement).value)}
/>
<button onClick$={() => {
state.todos.push(state.input);
state.input = '';
}}>
Add
</button>
<ul>
{state.todos.map((todo, i) => (
<li key={i}>{todo}</li>
))}
</ul>
</div>
);
});
If you know React, you can read Qwik. The $ is the only new concept.
5. Qwik City (Full-Stack Framework)
src/routes/
├── index.tsx → /
├── about/index.tsx → /about
├── blog/
│ ├── index.tsx → /blog
│ └── [slug]/index.tsx → /blog/:slug
└── layout.tsx → Layout wrapper
// src/routes/blog/[slug]/index.tsx
import { routeLoader$ } from '@builder.io/qwik-city';
export const usePost = routeLoader$(async ({ params }) => {
const post = await db.posts.findUnique({ where: { slug: params.slug } });
return post;
});
export default component$(() => {
const post = usePost();
return <article>{post.value.title}</article>;
});
Qwik vs React vs Astro
| Qwik | React | Astro | |
|---|---|---|---|
| JS on load | ~1KB | 80KB+ | 0KB |
| Interactivity | Resumable | Hydration | Islands |
| Scales with size | Yes (lazy) | No (more JS) | Partial |
| SPA navigation | Yes | Yes | Optional |
| Full-stack | Qwik City | Next.js | SSR mode |
Getting Started
npm create qwik@latest
The Bottom Line
Qwik's resumability is a paradigm shift. Your app can be infinitely complex, and users still get instant load times. If performance is your priority, Qwik eliminates the trade-off between features and speed.
Need data solutions? I build scraping tools. Check my Apify actors or email spinov001@gmail.com.
Top comments (0)