Alternative Frameworks & Their Performance Models

Astro: Zero-JS by Default

Astro (covered architecturally in Section 8) is the leading implementation of Islands Architecture and the top choice for content-heavy websites where performance is the primary concern. By default, Astro ships zero JavaScript to the browser — every component renders to static HTML at build time. Interactivity is opt-in via client directives (client:load, client:idle, client:visible, client:media), each of which controls when the island hydrates. This produces the best possible Core Web Vitals for content sites: Astro achieved a 99.2 average Lighthouse score in the Enterspeed benchmark study.

Astro 5 (released late 2024) introduced Content Layer for managing content collections from any source, Server Islands (dynamic server-rendered components within static pages), and improved View Transitions for cross-page animations. Astro’s killer feature for mixed teams is framework-agnostic component support — you can use React, Vue, Svelte, SolidJS, and Preact components in the same project, each hydrated as an independent island. This makes Astro ideal for incremental migrations where you’re moving from a React SPA to a content-first architecture without rewriting components. For the ultimate performance combination, use Qwik components inside Astro — they require no hydration directive at all because Qwik’s resumability eliminates the hydration step entirely.

Resources:

Svelte 5: Compiled Reactivity with Runes

Svelte takes a fundamentally different approach from React and Vue: it’s a compiler that transforms declarative component code into highly optimized imperative JavaScript at build time. There’s no virtual DOM, no runtime framework code, and no diffing algorithm. When state changes, Svelte surgically updates only the specific DOM nodes affected. The result: bundles as small as 3KB for simple apps, 15–30% smaller than equivalent React builds, and faster startup because there’s no framework to initialize.

Svelte 5 introduced Runes — a new reactivity system powered by signals under the hood. Runes replace Svelte 4’s “magic” reactivity (where let declarations were automatically reactive, but only inside .svelte files) with explicit, universal primitives that work everywhere — in .svelte files, .js files, and .ts files:

  • $state(value) — declares reactive state (replaces let)
  • $derived(expression) — computed values that update when dependencies change (replaces $:)
  • $effect(() => ...) — side effects that re-run when dependencies change (no dependency arrays needed — Svelte tracks them automatically)
  • $props() — declares component props

This shift to explicit reactivity solves Svelte 4’s key limitation: reactive logic couldn’t be extracted into reusable .js files because the compiler magic only worked inside .svelte components. Runes unlock universal, fine-grained reactivity that can be shared across components, moved to utility files, and composed freely. The signals-based implementation also enables more targeted updates — changing one item in a large list no longer invalidates the others.

SvelteKit is Svelte’s meta-framework, providing SSR, SSG, filesystem-based routing, and server-side data loading. Summer 2025 updates introduced Remote Functions (type-safe server functions callable from the client — similar to React Server Actions), async components for progressive rendering, and Vite as the build engine. SvelteKit deploys to Vercel, Cloudflare Workers, Netlify, Deno, and Node.js. For teams evaluating alternatives to React + Next.js, Svelte + SvelteKit offers the most dramatic reduction in JavaScript payload with the least change to the development model.

Resources:

SolidJS: Fine-Grained Reactivity Without the Virtual DOM

SolidJS looks like React on the surface — JSX, functional components, hooks-like APIs — but works fundamentally differently under the hood. Components run once to set up reactivity, then never re-execute. Instead of re-rendering entire component trees like React, SolidJS uses signals (createSignal) that directly track which specific DOM nodes depend on which pieces of state. When a signal changes, only the exact DOM nodes that read that signal update — no virtual DOM, no diffing, no component re-renders.

The performance implications are dramatic. Benchmarks show SolidJS is 50–70% faster than React in high-load scenarios (large tables, frequent updates), with 3× smaller initial bundle sizes. There are no dependency arrays, no useMemo, no useCallback — the reactive graph handles optimization automatically. For real-time dashboards, data visualization, and applications with hundreds of frequently updating DOM nodes, SolidJS’s fine-grained model provides performance that React’s architecture fundamentally cannot match, even with the React Compiler.

However, the mental model requires care: don’t destructure props (it breaks reactivity), don’t use ternaries for conditional rendering (use <Show> and <For> control-flow components), and understand that component functions run once, not on every update. The ecosystem is significantly smaller than React’s — fewer UI libraries, form solutions, and third-party integrations. SolidStart is the meta-framework (analogous to Next.js) providing SSR, routing, and server functions. Ryan Carniato (SolidJS creator, Principal Engineer at Netlify) is actively developing Solid 2.0 with a new @solidjs/signals package that extends the reactive model further. SolidJS’s ideas have been profoundly influential — Angular adopted signals, Svelte moved to signals-based runes, and even React’s Compiler is a response to the performance pressure signals created.

Resources:

Qwik: Resumability at Scale

Qwik’s performance model (covered in Section 8) eliminates hydration entirely through resumability — the server serializes the application’s execution state into HTML, and the client resumes from exactly where the server left off. Every event handler, closure, and component is automatically code-split into its own lazy-loadable chunk. JavaScript downloads only when a user interacts with a specific element, meaning the amount of JavaScript executed at startup is effectively zero regardless of application size.

This architecture produces the best possible INP and TBT scores because the main thread is never blocked by hydration. For applications where instant interactivity matters — e-commerce sites, content platforms, complex interactive applications — Qwik delivers near-zero Time to Interactive without sacrificing functionality. The $ suffix convention (e.g., component$, onClick$) marks resumability boundaries, which is the primary DX trade-off. Qwik City is the meta-framework providing routing, data loading, and middleware.

Qwik’s influence extends beyond its own adoption. The concept of resumability has pushed the entire ecosystem to question whether hydration is a necessary cost, and the Astro + Qwik combination (islands without hydration) demonstrates how these ideas compose with other architectures.

Resources:

Angular Signals and Modern Angular

Angular, historically the heaviest of the major frameworks, has undergone a dramatic modernization. Angular Signals (introduced in Angular 16, stabilized in 17+) bring fine-grained reactivity to Angular — replacing the framework’s traditional change detection mechanism (Zone.js, which monkey-patches all async APIs to trigger global change detection) with targeted, signal-based updates. Signals in Angular work similarly to SolidJS: mark state as a signal(), derive values with computed(), and react to changes with effect(). Components using signals can opt out of Zone.js entirely, significantly reducing runtime overhead and bundle size.

Additional modernizations include standalone components (no NgModules required), control flow syntax (@if, @for, @switch instead of structural directives), deferred views (@defer for built-in lazy loading with viewport/interaction/idle triggers), and improved SSR with hydration. Angular’s opinionated structure (dependency injection, TypeScript-first, built-in testing) continues to make it the default choice for large enterprise teams, but the performance gap with lighter frameworks has narrowed substantially with signals and Zone-less rendering.

Resources:

The Two Philosophies: Compiler Optimization vs. Fine-Grained Reactivity

The JavaScript framework landscape in 2026 has split into two competing performance philosophies. On one side, React’s compiler-driven approach: components re-render from top to bottom on state changes (the virtual DOM model), but the React Compiler automatically applies memoization at build time to prune unnecessary work. On the other side, signal-based fine-grained reactivity (SolidJS, Svelte 5, Angular, Qwik, Vue): reactive primitives track dependencies at the variable level, and only the specific DOM nodes or computations that depend on changed data update.

As Ryan Carniato noted at JSNation 2025, adding signals on top of a virtual DOM framework (like MobX in React, or Preact Signals) doesn’t reliably improve performance — the VDOM reconciliation overhead remains. The performance gains of signals require fine-grained rendering that eliminates VDOM entirely. The React Compiler is React’s answer to this competitive pressure: it automates optimization within the VDOM model rather than replacing it. Both approaches produce excellent results in practice; the choice depends on your team’s existing expertise, ecosystem needs, and whether you prioritize React’s massive library ecosystem or the raw performance and smaller bundles of signal-based alternatives.

Resources: