Benchmarks

The same table app, written once per framework, driven through the same operations in the same browser on the same machine. Vanilla JavaScript is the baseline; every other number is shown with its ratio to that.

Measured
October 4, 2026
Machine
Intel(R) Xeon(R) Processor @ 2.90GHz, 2 cores, 8 GB (Vercel build machine)
Browser
HeadlessChrome/153.0.8010.0
Versions
Loom 0.20.2 · React 19.3.0 · Vue 3 3.5.43 · Svelte 5 5.57.1 · Solid 1.9.15

DOM operations

OperationVanilla JSSvelte 55.57.1Solid1.9.15Loom0.20.2Vue 33.5.43React19.3.0
Create 1,000 rows44.9 ms1.00×51.2 ms1.14×50.5 ms1.12×56.8 ms1.27×44.1 ms0.98×46.2 ms1.03×
Replace all 1,000 rows47.9 ms1.00×51.5 ms1.08×49.9 ms1.04×69.2 ms1.44×49.8 ms1.04×56.4 ms1.18×
Update every 10th row10.0 ms1.00×8.40 ms0.84×15.4 ms1.54×11.3 ms1.13×11.0 ms1.10×10.1 ms1.01×
Select a row0.30 ms1.00×0.90 ms3.00×1.40 ms4.67×0.60 ms2.00×3.60 ms12.0×1.70 ms5.67×
Swap two rows5.50 ms1.00×5.90 ms1.07×5.80 ms1.05×6.80 ms1.24×9.10 ms1.65×69.2 ms12.6×
Remove a row4.10 ms1.00×4.40 ms1.07×3.90 ms0.95×4.40 ms1.07×5.20 ms1.27×5.40 ms1.32×
Clear 1,000 rows6.30 ms1.00×6.70 ms1.06×5.50 ms0.87×11.4 ms1.81×7.70 ms1.22×8.30 ms1.32×
Append 1,000 rows52.7 ms1.00×62.5 ms1.19×67.8 ms1.29×67.7 ms1.28×60.1 ms1.14×66.3 ms1.26×
Geometric mean of ratios1.00×1.21×1.32×1.37×1.58×1.93×

Bundle size

  • Vanilla JS
  • 1.5 kB gzip · 3.2 kB raw
  • Svelte 5
  • 20.6 kB gzip · 54.1 kB raw
  • Solid
  • 6.9 kB gzip · 16.6 kB raw
  • Loom
  • 14.0 kB gzip · 35.1 kB raw
  • Vue 3
  • 26.5 kB gzip · 66.7 kB raw
  • React
  • 68.7 kB gzip · 220.9 kB raw

Startup

FrameworkTime to first rendervs vanilla
Vanilla JS29.0 ms1.00×
Svelte 529.1 ms1.01×
Solid29.9 ms1.03×
Loom30.8 ms1.06×
Vue 332.1 ms1.11×
React43.4 ms1.50×

Memory

FrameworkHeap after 1,000 rowsvs vanilla
Vanilla JS1.0 MB1.00×
Svelte 52.3 MB2.23×
Solid2.0 MB1.94×
Loom2.5 MB2.51×
Vue 32.7 MB2.64×
React3.0 MB2.94×

Methodology

Each framework renders the same app: a toolbar and a table of 1,000 keyed rows with identical, seeded labels. The implementations are written the way each framework documents — keyed lists, memoized rows where the framework offers them — with no DOM work outside the framework.

A headless Chrome runner clicks the same buttons a user would. Each operation is timed in the page from just before the click until a forced synchronous layout after the microtask queue drains, so the number covers script, style and layout and excludes paint. Every operation runs 5 untimed warmups and 15 timed samples per framework, in round-robin order across the frameworks on a fresh page per operation; the table shows the median.

Startup is the time from navigation start to the frame after the app mounts, over 10 cold loads. Memory is the JavaScript heap after rendering 1,000 rows and a forced garbage collection. Bundle size is the minified JavaScript each app ships, raw and gzipped; the shared stylesheet is excluded.

The numbers are remeasured when a framework version or loom itself changes, on the machine named above. Absolute times move with the hardware; the ratios to vanilla JavaScript are the comparable part.

The bench app, runner and results schema are in the repository: apps/bench.