Qwik Cheat Sheet
Resumability-first framework syntax covering components, signals, $ lazy-loading boundaries, and routing in Qwik City.
component$ and Signals
Define a resumable component using fine-grained signals instead of a virtual DOM diff.
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 $ Lazy-Load Convention
Every $ suffix marks a symbol Qwik can extract into its own chunk and defer until interaction.
import { component$, useSignal, useVisibleTask$ } from '@builder.io/qwik'export const Widget = component$(() => { const ready = useSignal(false) // runs only once this component becomes visible client-side useVisibleTask$(() => { ready.value = true }) return ( <div onClick$={() => console.log('lazy handler loaded on click')}> {ready.value ? 'Hydrated' : 'Resumed, not hydrated'} </div> )})
Qwik City File-Based Route
Define a page and a server-side loader that streams data with zero client JS by default.
// src/routes/products/[id]/index.tsximport { component$ } from '@builder.io/qwik'import { routeLoader$ } from '@builder.io/qwik-city'export const useProduct = routeLoader$(async ({ params }) => { const res = await fetch(`https://api.example.com/products/${params.id}`) return res.json()})export default component$(() => { const product = useProduct() return <h1>{product.value.name}</h1>})
useStore and Context
Share deep reactive state across the tree without prop drilling.
import { component$, useStore, useContextProvider, createContextId, useContext } from '@builder.io/qwik'export const CartCtx = createContextId<{ items: string[] }>('cart')export const App = component$(() => { const cart = useStore({ items: [] as string[] }) useContextProvider(CartCtx, cart) return <Cart />})export const Cart = component$(() => { const cart = useContext(CartCtx) return <span>{cart.items.length} items</span>})
Core Qwik APIs
The hooks you'll reach for most.
- component$- defines a lazy-loadable, resumable component boundary
- useSignal- fine-grained reactive primitive, `.value` to read/write
- useStore- deep reactive object for structured state
- useTask$- server+client reactive side effect, runs during SSR and on dependency change
- useVisibleTask$- client-only effect, runs when the element enters the viewport (use sparingly)
- routeLoader$- server-only data loader colocated with a route, streamed to the client
routeAction$ with zod Validation
Handle form submissions server-side with automatic input validation and no client JS shipped for the happy path.
import { routeAction$, zod$, z, Form } from '@builder.io/qwik-city'export const useAddTodo = routeAction$( async (data, { fail }) => { if (data.title.length < 3) { return fail(400, { message: 'Title too short' }) } const todo = await db.todos.create({ title: data.title }) return { success: true, id: todo.id } }, zod$({ title: z.string().min(3).max(120), }))export default component$(() => { const action = useAddTodo() return ( <Form action={action}> <input name="title" /> {action.value?.failed && <p>{action.value.message}</p>} </Form> )})
useResource$ + Resource for Async Data
Fetch data reactively off a tracked signal and render loading/error/success states without a full useVisibleTask$ round trip.
import { component$, useSignal, useResource$, Resource } from '@builder.io/qwik'export const Search = component$(() => { const query = useSignal('') const results = useResource$<string[]>(({ track, cleanup }) => { const q = track(() => query.value) const controller = new AbortController() cleanup(() => controller.abort()) if (!q) return [] return fetch(`/api/search?q=${q}`, { signal: controller.signal }).then((r) => r.json()) }) return ( <> <input bind:value={query} /> <Resource value={results} onPending={() => <span>Loading…</span>} onRejected={(e) => <span>Error: {e.message}</span>} onResolved={(items) => <ul>{items.map((i) => <li key={i}>{i}</li>)}</ul>} /> </> )})
server$ Ad-Hoc RPC Functions
Turn any function into a server-only endpoint callable directly from a client event handler, without hand-writing a route.
import { component$, server$, useSignal } from '@builder.io/qwik'const getSecretStats = server$(async function () { // `this` gives access to the request event (cookies, headers, env) const apiKey = this.env.get('INTERNAL_API_KEY') const res = await fetch('https://internal.example.com/stats', { headers: { Authorization: `Bearer ${apiKey}` }, }) return res.json()})export const Stats = component$(() => { const stats = useSignal<any>(null) return ( <button onClick$={async () => (stats.value = await getSecretStats())}> Load stats </button> )})
Named Slots for Content Projection
Project multiple, independently-placed children fragments into a component, resumable across the projection boundary.
export const Card = component$(() => { return ( <div class="card"> <header><Slot name="header" /></header> <main><Slot /></main> <footer><Slot name="footer" /></footer> </div> )})export const Usage = component$(() => ( <Card> <h2 q:slot="header">Title</h2> <p>Default slot content goes to main</p> <button q:slot="footer">Close</button> </Card>))
Resumability & Optimizer Terms
Vocabulary you need once you go past basic components to understand how Qwik actually defers execution.
- QRL- a lazy, serializable reference (URL + symbol name) the optimizer generates for every $-suffixed closure
- Resumability- restoring app interactivity from serialized state in the HTML, with no re-execution of component render functions on load (contrast with hydration)
- useComputed$- derived, memoized signal recalculated only when its tracked dependencies change
- sync$- marks a handler that must run synchronously in the initial HTML (e.g. preventDefault on a link) before the full QRL loads
- useOn / useOnDocument / useOnWindow- attach lazy-loaded event listeners programmatically to the element, document, or window
- Qwik Insights- production click-stream data fed back into the optimizer to reorder the prefetch graph for real user paths
- q:slot- attribute marking which named <Slot> a projected child should be rendered into
Avoid `useVisibleTask$` unless you truly need client-only DOM/browser APIs — it forces JS to download and run, defeating the resumability model that makes Qwik's TTI near-zero.