A benchmark comparison and analysis between Qwik and Next.js 13. TL;DR 🔥 We’ll find out whether the trending framework Qwik is faster than Next.js 🤖 We’ll look at a demo that generates with OpenAI’s DALL-E and its performance benchmark. 🚀 We’ll discuss how Next.js leverages React server component to achieve fast SSR. Page speed matters. Faster website results in . The shows that optimizing leads to: better UX, better SEO, and more profit latest research done by Rekuten 24 Core Web Vitals 53.37% in revenue per visitor. 33.13% in conversion rate. 15.20% in average order value. 9.99% in average time spent. A 35.12% reduction in exit rate. The modern frameworks and frontend libraries address speed and help developers ship better user experiences to the users. We’ll be discussing two of the modern frameworks: and . We’ll see an experiment benchmark and look into how each framework achieves optimal performance. Qwik Next.js Let’s go. How The Experiment Is Set Up qwik v0.16 Next.js v13 React v18 Let’s Peek The Result I built two identical applications with Qwik and Next.js and measured the performances. The demo look like this: You can find . Feel free to take a look at the repo and try it out✨ the demo on GitHub The application lets users enter prompts to , an AI image generator, and displays the generated AI images in the page. It also displays the latest Twitter feed about DALL·E. DALL·E The key features are: Server Side rendering of the application. Client-side fetching the image results with . DALL·E’s REST API Server side fetching the Twitter feed with . Twitter’s REST API Here’s the core Web Vitals by Lighthouse for Qwik: Comparing to Next.js’s Web Vitals: We can observe the following: Qwik’s is 0.5 s faster than Next.js. speed index Qwik’s is 0.3 s faster than Next.js. time to interactive Next.js has a 0 ms , compared to Qwik’s 160 ms. total blocking time Next.js has a slightly higher overall by 5 points. performance score Next.js’s is 0.8 s faster than Qwik. largest contentful paint Let’s take a closer look at how the application in each framework is set up. Qwik Server-Side Rendering The component structure: // qwik/src/routes/index.tsx export const onGet: RequestHandler<TwitterResponse> = async () => { const data = await fetchTweets(); return data; } export default component$(() => { const tweets = useEndpoint<TwitterResponse>(); return ( <Layout> <DallePromptAndResult /> <Resource value={tweets} onResolved={(result) => ( <SSRTwitterCarousel data={result} /> )} /> <StaticPromptRecommendation /> </Layout> ) }) When the Qwik server receives a page request, it starts the rendering process on the server. The “useEndPoint” function invokes the “onGet” function on the server and fetches the Twitter feed. The “Resource” component will pause the rendering until the Twitter data is resolved or rejected. Once the rendering is completed, the server responds to the client with rendered HTML. We can observe the server-side rendering behavior in the performance profile: The lead time to respond to the client is blocked by the server side data fetching and component rendering. Next.js SSR and Streaming The component structure: // next/app/page.tsx export default async function Page() { const tweets = await fetchTweets(); return ( <Layout> <DallePromptAndResult /> <Suspense fallback={<Skeleton />}> <SSRTwitterCarousel data={tweets} /> </Suspense> <StaticPromptRecommendation /> </Layout> ) } The “Page” component is a server component. It looks just like a normal component but it supports async/await. When the Next.js server receives a page request, it starts the rendering process and s the rendering result to the client so that the client can progressively render and display the UI to the users. While the server is fetching Twitter feeds, React renders the suspense placeholder to indicate the pending state. Once the data is resolved or rejected, React reveals the suspense boundary and displays the final UI. stream You can see the client starts rendering while the server is streaming. It reduces the lead time for the users to start seeing the page. Resumability v.s. React Server Component Qwik embraces the “Get HTML and render” mental model. is Qwik’s innovation. It allows an application to be rendered as much as possible on the server and resumes the rest of the rendering on the client. Resumability The framework looks like this: When receiving a request, the Qwik server starts the rendering process and generates serialized application state, serialized event handlers, component HTMLs, and component code chunks. The server then responds to the client with the page HTML and the serialized state. On the client, the browser processes the and displays the UI. Qwik deserializes the state after the page HTML is loaded. The state contains all the local states of each component. The lazy-loaded components are able to be dynamically imported independently without knowing the parent’s state because they can refer to the deserialized state for their local states when they are rendering on the client. critical rendering path Qwik also serializes event handlers. In the server-generated HTML, the event handlers are referenced as dynamic JavaScript chunks. When users interact with an interactive element, Qwik uses the reference to dynamically download the chunk from the server and fire the event with the event handler inside the chunk. On the other hand, Next.js has a different approach to server-side rendering. Next.js and React server component promotes the “Render while fetching” mental model. . is a special type of component that can only be rendered on the server. Combining with Suspense and Streaming, the framework is able to progressively render interactive UI while avoiding long data requests from blocking the page rendering. Next.js 13 introduces React server component as an experimental feature Server component The framework looks like this: When Next.js server receives a request, it delegates React to handle rendering. On the server, React renders the component tree into a UI description in JSON instead of native HTML. The UI description describes the entire component tree. For the client components, React describes them as components for the client to handle with serialized props. For the server components, React renders them to native HTMLs and places them in the UI description. On the client, React receives and reconciles the UI description in the response stream to progressively render the UI. When React sees a suspense boundary, it renders the suspense placeholder until the pending data is resolved and reveals the suspense boundary. Because React receives a UI description instead of native HTML on the client, it needs to construct the component tree, render the UI, and attach event handlers on the client. It’s known as hydration. Final Thoughts Qwik’s concept of is very innovative. The client is able to render the page with just HTML and minimal JavaScript. It reduces the amount of JavaScript the client needs to download for the initial load and leverages dynamic import to download event handlers and components on the fly. We can clearly observe the benefit from the benchmark and performance profile. serializing states and event handlers However, the combination of React server component, suspense, and streaming has a profound impact on user experience. Users are able to see and interact with the content of the page without waiting for server-side data fetching to complete. The result of the experiment is not conclusive to me. Both frameworks performed well in the benchmarks. The differences in First Content Paint, Largest Content Paint, and Cumulative Layout Shift are likely a result of different Twitter images. References — OpenAI API Reference: Create image — web.dev Case Study — MDN Critical rendering path — OpenAI DALL·E 2 — Next.js Data Fetching Fundamentals — Andrew Clark First class support for promises — web.dev How Rakuten 24’s investment in Core Web Vitals increased revenue per visitor by 53.37% and conversion rate by 33.13% — Builder.io Hydration is Pure Overhead — Chrome Developers Lighthouse performance scoring — MDN Lazy loading — Vercel Next.js — OpenAI Node.js library — MDN Populating the page: how browsers work — Builder.io Progressively — Builder.io qwik — Daw-Chih Liou qwik-vs-next — React Community RFC: React Server Components — Builder.io Resumable vs. Hydration — Builder.io Reactivity — Next.js Server and Client Components — MDN The “why” of web performance — Builder.io Think Qwik — Chrome Developers Time to Interfactive — Chrome Developers Total Blocking Time — Twitter Developer Aplatform Twitter API v2 — web.dev Web Vitals — Chrome Developers Speed Index — Chrome Developers Largest Contentful Paint Want to Connect? This article was originally posted on__ __. Daw-Chih’s website Also Published Here