DEV Community

Alex Spinov
Alex Spinov

Posted on

Qwik City Has a Free API That Makes Resumable Web Apps Lightning Fast

Qwik is the framework that invented resumability — your app loads instantly because it never re-executes code the server already ran.

Routes: File-Based with Layouts

src/routes/
  layout.tsx          → Root layout
  index.tsx           → /
  products/
    layout.tsx        → Products layout
    index.tsx         → /products
    [id]/
      index.tsx       → /products/:id
Enter fullscreen mode Exit fullscreen mode

routeLoader$: Server Data

import { routeLoader$ } from "@builder.io/qwik-city";
import { component$ } from "@builder.io/qwik";

export const useProducts = routeLoader$(async ({ query }) => {
  const category = query.get("category");
  const res = await fetch(`https://api.example.com/products?category=${category}`);
  return res.json();
});

export default component$(() => {
  const products = useProducts();

  return (
    <div>
      {products.value.map((p) => (
        <div key={p.id}>
          <h3>{p.title}</h3>
          <span>${p.price}</span>
        </div>
      ))}
    </div>
  );
});
Enter fullscreen mode Exit fullscreen mode

routeAction$: Form Mutations

import { routeAction$, Form, zod$, z } from "@builder.io/qwik-city";

export const useCreateProduct = routeAction$(
  async (data, { fail }) => {
    const res = await fetch("https://api.example.com/products", {
      method: "POST",
      body: JSON.stringify(data),
    });
    if (!res.ok) return fail(500, { message: "Failed to create" });
    return { success: true };
  },
  zod$({
    title: z.string().min(1),
    price: z.number().positive(),
    url: z.string().url(),
  })
);

export default component$(() => {
  const action = useCreateProduct();

  return (
    <Form action={action}>
      <input name="title" required />
      <input name="price" type="number" required />
      <input name="url" type="url" required />
      <button type="submit">Create</button>
      {action.value?.success && <p>Created!</p>}
    </Form>
  );
});
Enter fullscreen mode Exit fullscreen mode

Signals: Fine-Grained Reactivity

import { component$, useSignal, useComputed$, useTask$ } from "@builder.io/qwik";

export default component$(() => {
  const filter = useSignal("");
  const products = useSignal<Product[]>([]);

  const filtered = useComputed$(() =>
    products.value.filter(p =>
      p.title.toLowerCase().includes(filter.value.toLowerCase())
    )
  );

  useTask$(({ track }) => {
    track(() => filter.value);
    console.log(`Filter changed: ${filter.value}`);
  });

  return (
    <div>
      <input bind:value={filter} placeholder="Search..." />
      {filtered.value.map(p => <ProductCard key={p.id} product={p} />)}
    </div>
  );
});
Enter fullscreen mode Exit fullscreen mode

Zero JS Until Interaction

Qwik serializes the app state into HTML. When a user interacts, only the relevant handler is lazy-loaded — not the entire app.

export default component$(() => {
  // This handler is ONLY loaded when the button is clicked
  const handleClick = $(() => {
    alert("Loaded on demand!");
  });

  return <button onClick$={handleClick}>Click me</button>;
});
Enter fullscreen mode Exit fullscreen mode

Build instant-loading data apps? My Apify tools + Qwik = zero-latency dashboards.

Custom solution? Email spinov001@gmail.com

Top comments (0)