DEV Community

Alex Spinov
Alex Spinov

Posted on

Qwik City Has a Free Full-Stack Framework: Instant Load Times With Resumability Instead of Hydration

Your Next.js app ships 200KB of JavaScript. Users on 3G wait 4 seconds staring at a blank screen while hydration runs. You code-split, lazy-load, optimize — and shave off maybe 500ms.

What if your framework shipped near-zero JavaScript by default, and only loaded code when the user actually interacted with something?

That's Qwik's resumability — and Qwik City is the full-stack framework built on it.

The Hydration Problem (and Qwik's Solution)

Traditional SSR frameworks:

  1. Server renders HTML → sends to browser
  2. Browser downloads ALL JavaScript
  3. Framework re-executes everything to attach event handlers (hydration)
  4. App becomes interactive

Qwik:

  1. Server renders HTML with serialized state → sends to browser
  2. App is immediately interactive — no hydration step
  3. JavaScript loads on-demand when user clicks/interacts

The result: sub-second TTI (Time to Interactive) regardless of app complexity.

Quick Start

npm create qwik@latest
cd qwik-app && npm start
Enter fullscreen mode Exit fullscreen mode

Resumable Components

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

export const Counter = component$(() => {
  const count = useSignal(0);

  return (
    <div>
      <p>Count: {count.value}</p>
      {/* This onClick handler's code loads ONLY when user clicks */}
      <button onClick$={() => count.value++}>
        Increment
      </button>
    </div>
  );
});
Enter fullscreen mode Exit fullscreen mode

The $ suffix is Qwik's marker for lazy-loading boundaries. The click handler code doesn't download until the user clicks the button. For a page with 50 buttons, that's 50 chunks that never load unless needed.

Server-Side Data Loading

// src/routes/products/index.tsx
import { routeLoader$ } from "@builder.io/qwik-city";

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

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

  return (
    <ul>
      {products.value.map((p) => (
        <li key={p.id}>{p.name} — ${p.price}</li>
      ))}
    </ul>
  );
});
Enter fullscreen mode Exit fullscreen mode

Server Actions — Form Handling Without Client JS

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

export const useAddToCart = routeAction$(async (data, { cookie }) => {
  await db.cart.add(data.productId, cookie.get("userId"));
  return { success: true };
});

export default component$(() => {
  const addToCart = useAddToCart();

  return (
    <Form action={addToCart}>
      <input type="hidden" name="productId" value="123" />
      <button type="submit">Add to Cart</button>
      {addToCart.value?.success && <p>Added!</p>}
    </Form>
  );
});
Enter fullscreen mode Exit fullscreen mode

Works without JavaScript enabled. Progressive enhancement by default.

Real-World Performance Impact

Metric Next.js (avg) Qwik City (avg)
JS shipped (initial) 180-350KB 1-5KB
TTI 2.1-4.5s 0.3-0.8s
Lighthouse Performance 65-85 95-100

When to Choose Qwik City

Choose Qwik when:

  • Page load speed directly impacts revenue (e-commerce, landing pages)
  • Your app is complex but most users only interact with a small part
  • Mobile/low-bandwidth users are a significant audience
  • You want SSR benefits without hydration cost

Skip Qwik when:

  • Your app is a highly interactive SPA (dashboards where all JS loads anyway)
  • You need React's massive component ecosystem
  • Team familiarity with React/Vue outweighs performance gains

The Bottom Line

Qwik City makes the "ship less JavaScript" philosophy automatic. You don't optimize — the framework does it by design. Every component, every handler, every piece of code is lazy-loaded at the interaction boundary.

Start here: qwik.dev


Need custom data extraction, scraping, or automation? I build tools that collect and process data at scale — 78 actors on Apify Store and 265+ open-source repos. Email me: Spinov001@gmail.com | My Apify Actors

Top comments (0)