Intro to Qwik

The Answer to Web App Scalability Issues

Doguhan Uluca

Principal Fellow  at


Modern Software Delivery

Have you had performance issues with your web app?

  • First Contentful Paint
  • Time to Interactive
  • Latency
  • Frame drops
  • Others?

Performance Indicators

The browser is a complicated runtime environment

The frameworks we use obfuscate the runtime in exchange for rich features and easier to maintain code

Frameworks of 2023 are really complicated in their own right

Credit Michael Hladky

Profiling Angular

Credit Michael Hladky

Profiling Angular

  • Downloading the JavaScript
    • App Code (Framework + 3rd party libraries)
  • Executing the JavaScript
    • Loading, JITing, and scaffolding all the code
  • Hydrating App Code
    • Compute the state, connect listeners to DOM, render
  • Change detection
    • Complicated component trees
  • Others?

What's Slowing Us Down?

Created by Miško Hevery @mhevery

Supported by

Adam Bradley @adamdbradley

Manu Corporat @manucorporat

5-10x faster websites

Full page load under 1 second, at scale

Easy to adopt (use 1 command/click)

Intro to Qwik

  1. The Need for Qwik
  2. Resumability
  3. Qwik Components
  4. Reactivity
  5. Tips for Starting with Qwik

The Need for Qwik


What's the fastest way to render a web page?

Possible Solutions

  1. Reduce use of 3rd party code
  2. Ahead of Time Compilation and code splitting
  3. Lazy load modules
  4. Server-side rendering
  5. Optimize each component by hand
  6. Remove features from your app
  7. Ditch JavaScript and deliver pure HTML

Credit Cube Drone


a minimalist

Qwik is a Minimalist

  • Tiny 1 KB framework
  • Aggressively delays download and execution of JS
  • Doesn't need to hydrate to start

Sandbags of Complexity

We Want Great DX

Qwik is Simple

  • No clever algo doing magic
  • Allows you to create reusable, resumable components
  • Familiar syntax to React


export const HelloWorld = component$(() => {
  return <div>Hello world</div>;
export const Button = component$(() => {
  return <button onClick$={() => console.log('click')}>Click me</button>;
export const LocalStateExample = component$(() => {
  const state = useSignal({
    value: 0,
  return <div>Value is: {state.value}</div>;

Server-Side Rendering (SSR) is expensive

Engineers are expensive

Experts are even more expensive

Qwik makes SSR easy

  • Resumable from a SSR rendered state
  • Components can be serialized, thus resumable
  • Progressive: Optimizer allows for fine grading lazy loading










/a: default















Component Legend




  • Framework state
    • Framework internals
    • Component trees
    • Listeners
  • App state
    • Parent component dependencies
    • User data


  • Expensive
  • Pure overhead
  • A fundamental architectural dependency


  • Seamlessly continue from SSR output
  • Enable async lazy loading
  • O(∞) → O(1)
  1. Efficiently deal with listeners
  2. Be able to independently restore components




Express listeners such that browser doesn't need to

eagerly load and process all listeners and event handlers

<button on:click="./chunk.js#handler_symbol">click me</button>

QRL (Qwik URL) points to a JS chunk to be lazily executed


Isolate dependencies, then serialize state into HTML



Qwik can serialize components and static/reactive state


  • Circular references

  • DOM references

  • Promises

  • Function closures
    (if wrapped in QRL)

  • Dates

  • URL objects

  • Map and Set instances

Not serializable

  • Classes
    (instanceof and prototype)

  • Streams


Qwik enforces scalable patterns

Developers don't need a crystal ball to optimize the application

Qwik Components


A Qwik Component

useSignal() or useStore() allows reactive state management

import { component$, useStore } from '';

export const MyCmp = component$((props: MyCmpProps) => {
  const count = useSignal(0);

  return (
        Hello, {} {count.value}
      <div>Times: {count.value}</div>
        onClick$={() => {

Component "Tree"

Components can use other components and pass values 

export const Counter = component$((props: {step?:number, initial?: number}) => {

export const MyApp = component$(() => {
  return (
      <div>Single: <Counter /></div>
      <div>Dozens: <Counter step={12}/></div>

How Component Isolation Works

Simple Parent-Child Relationship

export const Child = () => <span>child</span>;

const Parent = () => (
    <Child />
export const Child = component$(() => {
  return <span>child</span>;

export const Parent = component$(() => {
  return (
      <Child />

Wrap with component$()

Lazy Loading

Optimizer transformation

const Child = componentQrl(qrl('./chunk-a', 'Child_onMount'));
const Parent = componentQrl(qrl('./chunk-b', 'Parent_onMount'));
const Parent_onMount = () => qrl('./chunk-c', 'Parent_onRender');
const Parent_onRender = () => (
    <Child />




  • Latency 
  • Non-linear
  1. Pre-fetching
  2. Multi-threading
  3. Qwik City (Router): Speculative fetching, reducing network waterfalls



Component API

  • State
    • Static and Reactive
  • Events
    • Element, Window, or Document
  • Lifecycle Hooks
    • Task, Render, VisibleTask
  • Context
    • Shared state
  • Resource
    • Wrapper for asynchronously computed values

Component API

  • Slots
    • Content projection 
  • Rendering
    • Out-of-order and asynchronously 
  • Styling
    • Per component, scoped, global
  • Lite components 

Qwik Components

  • Isolated
  • Lazy loaded
  • Reactive



 Have you ever profiled

frame drops? 

Credit Michael Hladky

Change detection

Credit Michael Hladky

Assisting Change detection

Deep Expertise


  • Tracks which components are subscribed to a state
  • Invalidates only the relevant component on state change
  • Initial state is computed on the server, so browser doesn't need to re-render
  • No hydration means no need to re-build reactivity graph
  • Uses proxies for change detection (over zone.js or Virtual DOM)


Keeps track of subscription automatically

export const ComplexCounter = component$(() => {
  const state = useSignal({ count: 0, visible: true });

  return (
      <button onClick$={() => (state.visible = !state.visible)}>
        {state.visible ? 'hide' : 'show'}
      <button onClick$={() => state.count++}>increment</button>
      {state.visible ? <span>{state.count}</span> : null}

Can always compute the smallest set of invalidated components


  • Proxies also work on deep objects
  • Child components can be invalidated in a similar fashion


Reactivity enables best possible rendering performance

App performance doesn't suffer as the application grows in complexity

Tips for Starting with Qwik




Existing Codebases

  • Consider rebuilding your landing page with Qwik
  • Use Partytown to move all third-party scripts to web worker
  • Leverage Partytown integrations for React, Angular, Vue, Next.js and more


Qwik in 6 points

  1. Brings the developer closer to the metal, the DOM
  2. Qwik components are resumable and independent
  3. Surgically loads only the required bits of JS
  4. ... and does all that asynchronously
  5. ... and leverages web workers to free up the main thread
  6. Components only trigger re-render, when there's a state change


is a minimalist

We're hiring, including fully remote positions!

Intro to Qwik: The Answer to Web App Scalability Issues

By Doguhan Uluca

Intro to Qwik: The Answer to Web App Scalability Issues

At scale everything breaks. All the Angular and React in the world can't help, when even laws of physics break down at different scales. Qwik is an upcoming new framework to build web applications with O(1) scalability. It forgoes hydration in of favor resumability and embraces server-side-rendering in a seamless/magical way. Qwik has plans to implement React and Angular integrations in the future, so this is definitely a framework to watch and experiment with.

  • 646