Side-by-side comparison of 6 JavaScript frameworks using identical apps. Not synthetic benchmarks or hello worlds — actual apps you'd build at work.
10k row table, deep component tree, rapid state updates — measures raw rendering speed and reactivity.
Full task manager with filters, search, pagination, forms — measures real-world DX and ecosystem maturity.
Web terminal connected to a real shell via WebSocket — measures high-frequency DOM updates and lifecycle management.
| React | Vue | Svelte | Solid | Preact | Lit | |
|---|---|---|---|---|---|---|
| Routing | React Router v7 | Vue Router | SvelteKit | @solidjs/router | preact-router | Hash router |
| State | Zustand | Pinia | Svelte stores | createSignal | @preact/signals | LitElement @state |
| Server State | TanStack Query | TanStack Vue Query | fetch + load | createResource | signals | fetch + @state |
| Forms | React Hook Form + Zod | VeeValidate + Zod | Native + Zod | Native + Zod | Native + Zod | Native + Zod |
| Terminal | xterm.js | xterm.js | xterm.js | xterm.js | xterm.js | xterm.js |
| Styling | Tailwind v4 | Tailwind v4 | Tailwind v4 | Tailwind v4 | Tailwind v4 | Tailwind v4 |
Measured with Playwright headless Chromium. Median of 3 runs. All six apps render the same UI with the same data.
| Benchmark | React | Vue | Svelte | Solid | Preact | Lit |
|---|---|---|---|---|---|---|
| Create 10,000 rows | 828.8 | 270.4 | 472.1 | 235.3 | 301.0 | 278.9 |
| Update every 10th row | 258.3 | 49.5 | 35.4 | 53.7 | 78.9 | 45.4 |
| Swap rows | 194.7 | 47.7 | 45.7 | 27.9 | 80.6 | 33.9 |
| Select row | 250.6 | 29.0 | 15.6 | 222.9 | 55.1 | 18.1 |
| Append 1,000 rows | 211.6 | 69.3 | 97.8 | 47.2 | 102.9 | 74.7 |
| Clear all | 59.0 | 31.1 | 28.2 | 24.8 | 29.5 | 37.6 |
| App | React | Vue | Svelte | Solid | Preact | Lit |
|---|---|---|---|---|---|---|
| Perf Stress Test | 62.4 KB | 28.1 KB | 18.1 KB | 8.1 KB | 8.8 KB | 10.0 KB |
| Terminal Streamer | 135.3 KB | 99.6 KB | 87.4 KB | 79.1 KB | 81.5 KB | 82.5 KB |
Numbers will vary by machine. Run
pnpm dev:alland test yourself.
pnpm install
pnpm dev:all
Open http://localhost:1355 — dashboard with links to all 18 apps.
# Backends (needed for CRUD and Terminal apps)
pnpm dev:server:json # REST API on :3100
pnpm dev:server:pty # WebSocket terminal on :3200
# Performance
pnpm dev:perf:react # :5101
pnpm dev:perf:vue # :5102
pnpm dev:perf:svelte # :5103
pnpm dev:perf:solid # :5104
pnpm dev:perf:preact # :5105
pnpm dev:perf:lit # :5106
# CRUD
pnpm dev:crud:react # :5201
pnpm dev:crud:vue # :5202
pnpm dev:crud:svelte # :5203
pnpm dev:crud:solid # :5204
pnpm dev:crud:preact # :5205
pnpm dev:crud:lit # :5206
# Terminal
pnpm dev:xterm:react # :5301
pnpm dev:xterm:vue # :5302
pnpm dev:xterm:svelte # :5303
pnpm dev:xterm:solid # :5304
pnpm dev:xterm:preact # :5305
pnpm dev:xterm:lit # :5306
pnpm add-framework <name>
Generates all 3 apps with correct ports and TODO placeholders. See CONTRIBUTING.md for the full guide.
pnpm bench # all benchmarks
pnpm bench -- --app perf-stress --framework react # specific app/framework
pnpm bench -- --runs 10 # more iterations
Results are written to results/comparison.md.
pnpm e2e # 61 Playwright E2E tests across all apps
├── dashboard/ # Index page on :1355
├── apps/
│ ├── perf-stress/ # react/ vue/ svelte/ solid/ preact/ lit/
│ ├── crud/ # react/ vue/ svelte/ solid/ preact/ lit/
│ └── xterm/ # react/ vue/ svelte/ solid/ preact/ lit/
├── server/
│ ├── json/ # json-server for CRUD apps
│ └── pty/ # node-pty + WebSocket for terminal apps
├── bench/ # Playwright-based benchmark runner
├── shared/ # Types, benchmark utilities
└── e2e/ # E2E smoke tests
MIT