# Qwik — Instant-Loading Web Apps Without Effort
> Qwik is a web framework designed for instant-loading apps through resumability. Zero hydration, fine-grained code loading, and O(1) startup time — regardless of app size.
## Install
Save as a script file and run:
## Quick Use
```bash
# Create a new Qwik app
npm create qwik@latest
cd my-app
npm install
npm start
```
## Intro
**Qwik** is a new kind of web framework designed for the best possible time-to-interactive metric by focusing on resumability of server-side rendering of HTML, and fine-grained lazy-loading of code. Unlike traditional frameworks that need to "hydrate" (re-execute all component code on the client), Qwik can "resume" execution from where the server left off — resulting in instant page loads regardless of app complexity.
With 22K+ GitHub stars and MIT license, Qwik was created by Misko Hevery (also creator of Angular). It represents a fundamentally new approach to building web apps that scales to massive applications without sacrificing startup performance.
## What Qwik Does
- **Resumability**: Skip hydration entirely — apps resume from server state
- **O(1) Time-to-Interactive**: Startup time independent of app size
- **Fine-Grained Lazy Loading**: Auto-split code at function boundaries
- **Zero JS on Initial Load**: Interactive pages with 0 JavaScript
- **React-like Syntax**: JSX and component model familiar to React devs
- **Qwik City**: Meta-framework with routing, layouts, server actions
- **SSR/SSG/Static**: Flexible rendering modes
- **Optimized Bundles**: Automatic code splitting at event handler level
- **Signal-based**: Fine-grained reactivity like SolidJS
## Key Concept: Resumability
```
Traditional Hydration (React, Vue, etc.):
Server: Render HTML
Client: Download JS → Execute all components → Attach listeners → Interactive
Time: Proportional to app size
Qwik Resumability:
Server: Render HTML + serialize state
Client: No JS execution needed
User clicks button → Load ONLY that handler → Execute
Time: O(1) - constant regardless of app size
```
## Getting Started
### Create Project
```bash
npm create qwik@latest
# Choose:
# - my-app (name)
# - Basic App (template)
# - Select Qwik City (meta framework)
```
### Project Structure
```
my-app/
├── src/
│ ├── routes/ ← File-based routing
│ │ ├── index.tsx
│ │ ├── about/
│ │ │ └── index.tsx
│ │ └── blog/
│ │ └── [slug]/
│ │ └── index.tsx
│ ├── components/
│ │ └── header/
│ │ └── header.tsx
│ ├── root.tsx ← Root component
│ └── entry.ssr.tsx ← SSR entry
├── vite.config.ts
└── package.json
```
## Basic Components
### Counter Component
```tsx
import { component$, useSignal, $ } from '@builder.io/qwik';
export default component$(() => {
const count = useSignal(0);
return (
Counter: {count.value}
);
});
```
Note: `component$` and `onClick$` — the `$` marker tells Qwik to split this code for lazy loading.
### Important: Only Runs on Interaction
```tsx
import { component$, useSignal } from '@builder.io/qwik';
export default component$(() => {
const count = useSignal(0);
// This console.log runs on server during SSR
console.log('Component setup');
return (
Count: {count.value}
);
});
```
### Async Data with useResource$
```tsx
import { component$, useResource$, Resource } from '@builder.io/qwik';
export default component$(() => {
const postsResource = useResource$(async () => {
const res = await fetch('https://api.example.com/posts');
return res.json();
});
return (
Loading...
}
onRejected={(error) =>
Error: {error.message}
}
onResolved={(posts) => (
{posts.map((post) =>
{post.title}
)}
)}
/>
);
});
```
## Qwik City (Meta Framework)
### File-Based Routing
```tsx
// src/routes/blog/[slug]/index.tsx
import { component$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
// Runs on server before rendering
export const useBlogPost = routeLoader$(async ({ params }) => {
const post = await db.post.findUnique({ where: { slug: params.slug } });
return post;
});
export default component$(() => {
const post = useBlogPost();
return (
{post.value?.title}
);
});
```
### Server Actions
```tsx
import { component$ } from '@builder.io/qwik';
import { Form, routeAction$, z, zod$ } from '@builder.io/qwik-city';
// Server-side action
export const useCreatePost = routeAction$(
async (data, { redirect }) => {
const post = await db.post.create({ data });
throw redirect(302, `/blog/${post.slug}`);
},
zod$({
title: z.string().min(1),
content: z.string().min(10),
})
);
export default component$(() => {
const createPost = useCreatePost();
return (
);
});
```
### Layouts
```tsx
// src/routes/layout.tsx
import { component$, Slot } from '@builder.io/qwik';
export default component$(() => {
return (
<>
My Site {/* Child routes render here */}
>
);
});
```
## Performance Characteristics
```
Initial Page Load (Traditional React):
HTML: 10KB
JS: 300KB+ (React + app code)
Time-to-Interactive: 2-5 seconds
Initial Page Load (Qwik):
HTML: 15KB (includes serialized state)
JS: 0KB (nothing to execute!)
Time-to-Interactive: ~0 seconds
When user interacts:
Download 3KB chunk for specific handler
Execute handler
Update DOM
```
## Why Resumability?
Problem with hydration:
```
1. Server renders HTML (fast)
2. User sees content
3. Client downloads framework + components (slow)
4. Client RE-EXECUTES all components (builds VDOM)
5. Reconciles with existing DOM
6. Attaches event listeners
7. NOW interactive (1-5 seconds later)
Hydration = doing everything twice
```
Qwik solves this by:
```
1. Server renders HTML + serializes component state
2. Client sees content
3. Client needs ZERO JavaScript to be interactive
4. On first user interaction, download ONLY the specific handler
5. Execute handler, update DOM
6. Done
```
## Qwik vs Alternatives
| Feature | Qwik | React | Solid | Astro |
|---------|------|-------|-------|-------|
| Hydration | None (Resume) | Required | Required | Islands |
| Time-to-Interactive | O(1) | O(n) | O(n) | O(islands) |
| Initial JS | 0KB | Full bundle | Full bundle | Minimal |
| Syntax | JSX + $ markers | JSX | JSX | JSX/MD |
| Learning curve | Medium | Easy | Easy | Easy |
| Best for | Large apps | General | Performance | Content sites |
## 常见问题
**Q: Qwik 的 $ 符号是什么?**
A: `$` 是 Qwik 的"lazy loading boundary"标记。每个 `$` 标记的函数都会被编译成独立的 chunk,按需加载。这是 Qwik 实现细粒度代码分割的关键机制。
**Q: Qwik 和 Astro 怎么选?**
A: Astro 是"岛屿架构"——静态 HTML + 少量交互岛屿,适合内容网站。Qwik 是整个应用都是 resumable 的,适合有大量交互的 Web 应用。内容博客选 Astro,SaaS 应用选 Qwik。
**Q: 生态系统成熟吗?**
A: Qwik 相对较新(2022 发布),生态仍在成长中。但核心团队(包括 Angular 创造者)非常活跃,大公司如 Builder.io 在生产环境使用。对于追求极致性能的新项目很值得考虑。
## 来源与致谢
- GitHub: [QwikDev/qwik](https://github.com/QwikDev/qwik) — 22K+ ⭐ | MIT
- 官网: [qwik.dev](https://qwik.dev)
---
Source: https://tokrepo.com/en/workflows/baecf967-3559-11f1-9bc6-00163e2b0d79
Author: Script Depot