We’ve been wrestling with a performance paradox: we want to build rich, interactive web applications, but the process of getting them into the browser has become increasingly expensive. Hydration has slowly become one of our industry’s biggest performance bottlenecks.

I recently spent a weekend exploring this experimental framework, and I’m genuinely intrigued by its approach. While it’s definitely not production-ready yet, Qwik represents a fundamental rethinking of how we deliver JavaScript to the browser.

The Hydration Problem

If you’ve worked with React, Vue, or any modern framework that supports server-side rendering (SSR), you’re familiar with hydration. The server sends HTML to the browser for fast initial rendering, then ships a bundle of JavaScript that “rehydrates” the page, attaching event listeners and making it interactive.

The problem? This hydration process requires loading and executing a significant amount of JavaScript upfront - even for parts of the page the user might never interact with. With React 18’s improvements earlier this year and frameworks like Next.js and Remix optimizing the developer experience, we’ve mitigated some pain points, but the fundamental issue remains: hydration is expensive.

Just last week, I deployed a mid-sized Next.js application that took nearly 2 seconds to become interactive on mid-range mobile devices, despite all my optimization efforts with code splitting and lazy loading. The hydration tax was still too high.

Enter Qwik and Resumability

Qwik takes a fundamentally different approach. Instead of hydrating, it “resumes” the application exactly where the server left off.

The key insight is that Qwik serializes the application state and event listeners directly into the HTML, allowing the browser to pick up the application without needing to run through the component tree again. The most impressive part? It only loads the JavaScript required for the specific interaction a user initiates.

Here’s what makes Qwik’s approach revolutionary:

  1. No upfront JavaScript cost - Qwik applications can be fully interactive with virtually zero initial JavaScript.

  2. Fine-grained lazy loading - JavaScript loads only for the components that need to respond to user interactions, and only when those interactions occur.

  3. Preserving application state - The framework serializes component state directly into HTML, eliminating the need to rebuild it on the client.

How Resumability Works in Real-World UI

Let’s move beyond toy counters and todo lists to see how Qwik handles real-world UI components. Performance promises are easy with simple examples, but to truly appreciate Qwik’s approach, we need to look at more involved UI scenarios that reflect what actual frontends do.

Scenario 1: Search Suggestions with Lazy Filtering

Imagine a search input that displays suggestions by filtering a dataset fetched server-side:

import { component$, useStore, $ } from '@builder.io/qwik';

export const SearchWithSuggestions = component$(() => {
  const state = useStore({ query: '', results: [] });

  const onSearchInput = $((evt: KeyboardEvent) => {
    const value = (evt.target as HTMLInputElement).value;
    state.query = value;
    // simulate filtering large server-fetched list
    state.results = mockDataset.filter(item => 
      item.toLowerCase().includes(value.toLowerCase()));
  });

  return (
    <div>
      <input 
        placeholder="Type to search" 
        value={state.query}
        onInput$={onSearchInput}
      />
      {state.results.length > 0 && (
        <ul>
          {state.results.map(item => (
            <li key={item}>{item}</li>
          ))}
        </ul>
      )}
    </div>
  );
});

const mockDataset = ['Qwik', 'React', 'Vue', 'Svelte', 'Solid', 'Preact'];

In popular frameworks, the entire filtering logic and suggestion dropdown code gets bundled and hydrated immediately, affecting Time-to-Interactive even if the user never searches for anything. With Qwik, the input remains inert until someone types. On the first keystroke, only the filtering chunk loads, fetched lazily. No global hydration is needed.

The key is the onInput$ event handler, which is serialized into HTML and fetched lazily when the user first types. The static HTML already contains the serialized empty search state, and no global filtering logic loads initially.

Scenario 2: Modal Loaded and Activated On Demand

Modals often contain heavy UI elements like forms, tabs, and validators. In traditional frameworks, hydration demands all that JavaScript upfront. Qwik delays activation until the user actually triggers the modal:

import { component$, useStore, $ } from '@builder.io/qwik';

export const LazyModalExample = component$(() => {
  const state = useStore({ showModal: false, formData: { name: '' } });

  const openModal = $(() => state.showModal = true);
  const closeModal = $(() => state.showModal = false);

  const submitForm = $(() => {
    console.log('Submitted:', state.formData);
    state.showModal = false;
  });

  return (
    <div>
      <button onClick$={openModal}>Open Modal</button>

      {state.showModal && (
        <div class="modal-overlay" onClick$={closeModal}>
          <div class="modal-content" onClick$={(e) => e.stopPropagation()}>
            <h2>Fill the Form</h2>
            <input 
              placeholder="Name"
              value={state.formData.name}
              onInput$={$((e) => state.formData.name = (e.target as HTMLInputElement).value)}
            />
            <button onClick$={submitForm}>Submit</button>
            <button onClick$={closeModal}>Cancel</button>
          </div>
        </div>
      )}
    </div>
  );
});

Notice all event handlers are marked with $. This is Qwik’s way of indicating which functions should be split into separate chunks. These functions are automatically split into mini chunks that download only after the user triggers the modal or submits the form. By default, none of this code hits the initial bundle. Even the console.log() won’t end up on the client until the submit button is clicked.

How This Differs From Mainstream Frameworks

In both examples, the initial HTML contains serialized reactive state and event boundary markers—but almost zero interactive JavaScript bytes. Only minimal code for the exact interaction arrives on-demand later, unlike frameworks that hydrate the entire route or page regardless of user paths.

With traditional frameworks, even with code splitting, these frameworks typically load at least the component-level JavaScript upfront during hydration. Qwik’s approach means a user who never opens a modal or never types in a search box will never download the JavaScript for those interactions.

Current Limitations

Qwik is still in preview, and there are clear signs of its experimental status.

It’s also worth noting that Qwik works best when you build with it from the ground up. While there are adapters for using React components inside Qwik, you’ll get the best performance by fully embracing its paradigm.

Where Qwik Fits in Today’s Landscape

The frontend framework space is more vibrant than ever. We’ve seen Svelte and SolidJS challenge React’s rendering paradigm with compilation approaches. Astro has popularized the concept of “islands architecture” for partially hydrated apps. Next.js and Remix have pushed server-rendering to new heights.

What makes Qwik interesting is that it’s not just an incremental improvement - it’s questioning one of the fundamental assumptions of modern web development: that hydration is necessary.

Should You Try It?

If you’re a developer who enjoys exploring cutting-edge approaches and doesn’t mind some rough edges, Qwik is absolutely worth experimenting with. Create a small prototype or rebuild a section of an existing application to understand its paradigm.

While it is not ready for production applications just yet, tracking on Qwik’s development could give you valuable insights into where web performance optimization is heading. The concepts behind resumability might influence how you think about code splitting and lazy loading, even in your current framework.

Conclusion

Qwik represents one of the interesting attempts to solve the hydration problem I’ve seen. By fundamentally rethinking how JavaScript is delivered to the browser, it opens up possibilities for performance optimization that go beyond what traditional frameworks can achieve with incremental improvements.

Whether Qwik itself becomes mainstream or not, its approach to resumability rather than hydration is aligning to the next generation of web frameworks. As Core Web Vitals continue to impact both user experience and SEO, solutions like this that fundamentally address JavaScript performance will become increasingly valuable.