DEV Community

Cover image for Moving from Nextjs to Qwik
Jaime
Jaime

Posted on

Moving from Nextjs to Qwik

Whenever I’m working on a web application, Next.js is my go-to framework. I like it and I’m used to it, but I’ve been hearing a lot about Qwik and decided to give it a shot.

In my previous post, Exploring the Art Institute API and Gemini, I built the app using Next.js. Since it’s a new project, I thought it would be a good exercise to redo it using Qwik instead.

You can still access the previous version, and to make it a bit more interesting, I’m using Lighthouse to compare the two versions:

Both codebases render a static site, which is generated daily using a cron job and a deploy hook.

Network

Let’s start by looking at the Network tab:

Left is Next.js and right is Qwik

Network tab

This is very interesting because, in summary, Qwik sends fewer bytes to the browser, and fewer bytes translate into faster rendering as well, even though both apps show basically the same UI.

Next.js Qwik
Transferred 285 kB 118 kB
Resources 649 kB 172 kB
DomContentLoaded 92 ms 96 ms
Load 368 ms 124 ms
  • kB transferred is the data sent from the server (CDN) to the browser, which is zipped.
  • kB resources is the total size once unzipped.

As we can see, the Qwik project sends less data. This is a big win for Qwik.

  • DomContentLoaded is the event fired when the HTML is parsed and the DOM is built. At this point, JavaScript is executed and images and stylesheets start loading.
  • Load is the event fired when everything is ready. The browser doesn’t need to download anything else (images, styles, etc.), and the page is fully rendered.

Notice that while DomContentLoaded happens at almost the same time, Load happens much faster for Qwik. This is just how the framework works. In the case of Next.js, since the app is larger, it takes a bit longer to completely render the page.

Note: I checked the “Disable cache” checkbox to always download files from the origin (CDN).

Also keep in mind that these values change on every load. Things like browser cache, internet connectivity, and server response times are different every time. That’s why, when testing these values, a load test is a better approach. Loading the page N times gives you a better average. A single run can be influenced by chance. Still, these numbers are a great benchmark for any website.

Lighthouse

Performance

Lighthouse performance results

Right from the start, Qwik gets a perfect score of 100 across the board, while Next.js gets a slightly lower score. This is interesting because it’s not about the application code, but about the framework itself.

Sure, a Next.js application can also reach 100, but that usually requires extra work, which isn’t necessary when using Qwik.

Metrics

Lighthouse metrics results

Based on the results from the Network tab, it makes sense that these values are lower for Qwik. In simple terms: same UI, fewer bytes, faster rendering.

Diagnostics

Lighthouse diagnostics results

Here we can see Lighthouse pointing out that Next.js has some unused JavaScript. This doesn’t happen with Qwik, confirming that Qwik generates a leaner build.

Coding

This is my first time using Qwik, and I didn’t want to use AI agents to convert the code. I spent some time reading the Qwik documentation, and that was enough to build this simple app. Here are some findings:

Components

In Next.js, a function is a component, with no extra syntax needed:

export default function Home() {
  return <div>Home Page Component</div>;
}
Enter fullscreen mode Exit fullscreen mode

With Qwik, you need to use the component$ function:

export default component$(() => {
  return <div>Home Page Component</div>;
});
Enter fullscreen mode Exit fullscreen mode

Not a big deal. The syntax changes a bit, but it’s easy enough to follow.

State variables and clicks

In Next.js, we use useState along with "use client"; because state lives on the client. Similarly, onClick handlers only run on the client.

"use client";

import { useState } from "react";

export default function Home() {
  const [greeting, setGreeting] = useState("hello world");

  return <div onClick={() => setGreeting("hello from click")}>{greeting}</div>;
}
Enter fullscreen mode Exit fullscreen mode

Qwik uses useSignal for "signal variables" and onClick$ for click handlers:

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

export default component$(() => {
  const greetingSignal = useSignal("hello world");

  return (
    <div onClick$={() => (greetingSignal.value = "hello from click")}>
      {greetingSignal}
    </div>
  );
});
Enter fullscreen mode Exit fullscreen mode

Assigning a new value to greetingSignal.value = ... is equivalent to calling setGreeting(...), and it triggers a re-render.

Fetching data

In both cases, data is fetched on the server. Remember, the page is generated daily, meaning the server generates the HTML, which is then cached in the CDN and served to users. Once per day, the server fetches a JSON file.

Next.js:

export default async function Home() {
  const quiz = await fetch(`https://domain.com/name.json`).then((res) =>
    res.json()
  );

  return <Quiz quiz={quiz} />;
}
Enter fullscreen mode Exit fullscreen mode

Since there’s no "use client"; directive, this code runs only on the server.

Qwik:

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

export const useQuiz = routeLoader$(async () => {
  const response = await fetch(`https://domain.com/name.json`).then((res) =>
    res.json()
  );
  return response;
});

export default component$(() => {
  const quiz = useQuiz();

  return <Quiz quiz={quiz} />;
});
Enter fullscreen mode Exit fullscreen mode

With Qwik, routeLoader$ defines server-side logic, and the component consumes it as a hook.

Summary

Qwik is clearly a leaner framework than Next.js, and the syntax differences are minimal. Both frameworks share the same core concepts: components, state/signals, data fetching, and more.

One big advantage of Next.js is the size of its community.

At the time of writing:

Next.js Qwik
GitHub stars 137k 21.9k
GitHub watchers 1.5k 135
GitHub pull requests 1.2k 43
NPM weekly downloads 15.5 million 16.3 thousand

It’s easy to see that the Next.js community is much larger, which means better ecosystem support, more documentation, and more tooling.

For my personal projects, I’ll definitely keep using Qwik to get more familiar with it. In a professional environment, I’ll stick with Next.js. Just because a framework does something better doesn’t justify the cost of refactoring existing code. Even with AI agents helping, refactoring still involves testing, monitoring, and maintenance. Shaving off a fraction of a second usually isn’t worth the investment—unless you’re in the business of speed, like e-commerce, streaming, or other high-traffic services. Even then, there are often alternatives besides switching frameworks.

Finally, now that a lot of code is written by AI agents, I don’t think the framework choice matters. What really matters is keeping things like reusability, scalability, performance, and design patterns in mind.

It’s not about the framework, it’s about the solution.

That’s it—happy coding.

Top comments (0)