Benchmarks
js-framework-benchmark
The keyed benchmark, run with krausest's own runner. Try the same Lumiose app in your browser, or read how the numbers were measured.
Generated by pnpm bench:jsfb (benchmarks/js-framework-benchmark/scripts/jsfb.ts): krausest's own
webdriver-ts runner (Puppeteer, Chrome trace timing, upstream CPU throttling and memory
measurement), krausest commit bf894b6, headless Chrome.
- Date: 2026-10-12 13:17 UTC
- Machine: Apple M1 Max (10 cores), darwin 27.0.0
- Browser: Google Chrome 154.0.8037.99
- Iterations: 10 per CPU benchmark, 3 per memory benchmark (medians shown)
- Framework versions (pinned in scripts/jsfb.ts and frameworks/keyed/*/package.json): solid 1.9.17, solid-2 (RC) 2.0.0-rc.14, svelte 5.57.2, vue 3.5.43, vue-vapor (RC) 3.6.0-rc.11, preact-hooks 11.0.1, react-hooks 19.3.0, remix-v3 3.0.0
- lumiose: src/App.stsx compiled by @lumiose/vite; lumiose-hand: the same app hand-compiled from the compiler-runtime contract (src/hand-compiled.js), the target for the compiler's output
- solid-2 (RC): frameworks/keyed/solid-2, krausest's solid entry ported to the Solid 2 release candidate (createProjection for the selection, automatic batching), compiled with the matching @solidjs/babel-plugin; a pre-release, shown next to stable Solid. krausest has no Solid 2 entry
- vue-vapor (RC): Vue Vapor only ships in the Vue 3.6 release candidates
- remix-v3: frameworks/keyed/remix-v3, [email protected] (remix/component 1.0) bundled and minified by esbuild like the Remix team's own benchmark app; krausest has no Remix 3 entry, so it has no published factor
CPU (median total ms, factor vs the fastest framework here)
| benchmark | lumiose | lumiose-hand | vanillajs | solid | solid-2 (RC) | svelte | vue | vue-vapor (RC) | preact-hooks | react-hooks | remix-v3 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 01_run1k create rows | 29.6 (1.03) | 29.3 (1.02) | 28.8 (1.00) | 29.9 (1.04) | 30.3 (1.05) | 30.9 (1.07) | 34.0 (1.18) | 30.6 (1.06) | 35.8 (1.24) | 36.0 (1.25) | 37.0 (1.28) |
| 02_replace1k replace all rows | 33.4 (1.04) | 33.5 (1.04) | 32.0 (1.00) | 34.8 (1.09) | 35.3 (1.10) | 36.5 (1.14) | 39.8 (1.24) | 34.5 (1.08) | 43.8 (1.37) | 43.7 (1.36) | 41.5 (1.29) |
| 03_update10th1k_x16 partial update (4x slowdown) | 17.4 (1.17) | 16.0 (1.07) | 14.9 (1.00) | 17.4 (1.17) | 17.7 (1.19) | 18.7 (1.26) | 18.8 (1.26) | 16.2 (1.09) | 30.1 (2.02) | 22.3 (1.49) | 33.2 (2.23) |
| 04_select1k select row (4x slowdown) | 6.0 (1.33) | 5.3 (1.18) | 4.5 (1.00) | 6.2 (1.37) | 6.3 (1.41) | 9.2 (2.04) | 6.9 (1.53) | 4.8 (1.08) | 21.1 (4.70) | 8.8 (1.94) | 28.9 (6.41) |
| 05_swap1k swap rows (4x slowdown) | 19.9 (1.14) | 19.0 (1.10) | 17.4 (1.00) | 20.6 (1.19) | 21.1 (1.22) | 21.3 (1.23) | 20.9 (1.20) | 19.9 (1.15) | 32.8 (1.89) | 139.4 (8.04) | 36.2 (2.09) |
| 06_remove-one-1k remove row (2x slowdown) | 16.4 (1.06) | 15.4 (1.00) | 15.4 (1.00) | 16.6 (1.07) | 16.6 (1.07) | 16.9 (1.10) | 19.1 (1.24) | 16.3 (1.06) | 22.8 (1.48) | 18.3 (1.19) | 25.6 (1.67) |
| 07_create10k create many rows | 328.3 (1.08) | 328.4 (1.08) | 305.3 (1.00) | 327.1 (1.07) | 330.5 (1.08) | 334.9 (1.10) | 369.4 (1.21) | 329.1 (1.08) | 394.1 (1.29) | 590.4 (1.93) | 403.0 (1.32) |
| 08_create1k-after1k_x2 append rows to large table | 35.2 (1.03) | 34.6 (1.01) | 34.2 (1.00) | 36.0 (1.06) | 36.3 (1.06) | 37.0 (1.08) | 39.8 (1.16) | 35.8 (1.05) | 44.7 (1.31) | 42.8 (1.25) | 47.2 (1.38) |
| 09_clear1k_x8 clear rows (4x slowdown) | 14.9 (1.10) | 14.8 (1.10) | 13.6 (1.00) | 16.3 (1.20) | 16.9 (1.24) | 16.9 (1.24) | 19.2 (1.42) | 15.1 (1.11) | 19.4 (1.43) | 25.4 (1.88) | 15.9 (1.17) |
| weighted geometric mean (local factors) | 1.082 | 1.050 | 1.000 | 1.107 | 1.123 | 1.170 | 1.247 | 1.076 | 1.520 | 1.541 | 1.573 |
| projected published factor | 1.132 | 1.098 | 1.046 | 1.158 | 1.175 | 1.223 | 1.303 | 1.125 | 1.590 | 1.612 | 1.645 |
| published factor (krausest's table) | – | – | 1.046 | 1.133 (v1.9.3) | – | 1.182 (v5.42.1) | 1.311 (v3.5.39) | 1.114 (v3.6.0-rc.5) | 1.647 (v11.0.0) | 1.595 (v19.2.0) | – |
krausest's published table measured its own pinned versions: where a published factor names a version, krausest measured that version and this run measured the newer one listed above.
The projected factor calibrates each local time against vanillajs's factor in krausest's
published table (webdriver-ts/results.json, same Chrome major; vanillajs has no version):
(local / local vanillajs) × (published vanillajs / published fastest), then krausest's
weighted geometric mean. It is the number to compare with the spec targets (doc-1 §11:
CPU ≤ 1.12; published vanillajs 1.05, Solid 1.13).
Script time (median ms)
| benchmark | lumiose | lumiose-hand | vanillajs | solid | solid-2 (RC) | svelte | vue | vue-vapor (RC) | preact-hooks | react-hooks | remix-v3 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 01_run1k | 3.1 | 2.9 | 2.6 | 3.7 | 4.0 | 4.5 | 7.4 | 4.0 | 9.4 | 9.4 | 10.5 |
| 02_replace1k | 5.8 | 5.8 | 5.1 | 7.3 | 7.8 | 9.1 | 11.8 | 6.8 | 15.9 | 15.6 | 13.8 |
| 03_update10th1k_x16 | 1.1 | 1.1 | 0.6 | 1.5 | 2.5 | 2.7 | 3.5 | 1.4 | 14.1 | 5.9 | 18.0 |
| 04_select1k | 0.7 | 0.6 | 0.4 | 1.1 | 1.9 | 4.4 | 1.9 | 0.7 | 15.0 | 3.8 | 22.6 |
| 05_swap1k | 1.0 | 0.8 | 0.3 | 1.9 | 2.3 | 2.5 | 2.0 | 1.6 | 13.3 | 29.5 | 17.9 |
| 06_remove-one-1k | 0.5 | 0.5 | 0.5 | 0.6 | 0.9 | 1.1 | 3.5 | 0.9 | 7.1 | 1.9 | 9.6 |
| 07_create10k | 32.6 | 32.3 | 23.9 | 32.6 | 35.3 | 38.3 | 66.9 | 33.3 | 90.9 | 282.4 | 94.1 |
| 08_create1k-after1k_x2 | 3.0 | 2.9 | 2.6 | 4.0 | 4.4 | 4.8 | 7.5 | 4.1 | 12.5 | 10.4 | 15.6 |
| 09_clear1k_x8 | 11.7 | 11.6 | 10.4 | 13.3 | 13.6 | 13.8 | 15.9 | 11.8 | 16.1 | 22.6 | 12.9 |
Memory (MB, median)
| benchmark | lumiose | lumiose-hand | vanillajs | solid | solid-2 (RC) | svelte | vue | vue-vapor (RC) | preact-hooks | react-hooks | remix-v3 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 21_ready-memory ready memory | 0.62 | 0.62 | 0.57 | 0.60 | 0.74 | 0.69 | 0.87 | 0.78 | 0.64 | 1.21 | 0.87 |
| 22_run-memory run memory (1k rows) | 2.59 | 2.47 | 1.87 | 2.68 | 2.95 | 3.01 | 3.93 | 3.14 | 3.34 | 4.44 | 4.26 |
| 25_run-clear-memory create/clear 1k rows (5 cycles) | 0.80 | 0.82 | 0.65 | 0.77 | 1.17 | 1.06 | 1.20 | 1.10 | 0.82 | 2.06 | 1.25 |
Spec target: run memory ≤ 2.7 MB (stretch 2.5).
Size and startup
| benchmark | lumiose | lumiose-hand | vanillajs | solid | solid-2 (RC) | svelte | vue | vue-vapor (RC) | preact-hooks | react-hooks | remix-v3 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 41_size-uncompressed uncompressed size (kB) | 18.0 | 17.7 | 11.3 | 11.6 | 59.1 | 32.6 | 65.8 | 58.3 | 14.9 | 219.1 | 88.5 |
| 42_size-compressed compressed size (kB) | 6.4 | 6.2 | 2.5 | 4.5 | 19.8 | 11.6 | 23.8 | 20.4 | 6.0 | 58.7 | 25.5 |
| 43_first-paint first paint (ms) | 56.9 | 51.7 | 58.1 | 56.7 | 91.6 | 72.2 | 126.4 | 107.5 | 60.0 | 316.2 | 140.9 |
- lumiose bundle (dist/main.js, runtime and app): min 17.72 kB, gzip 6.63 kB, brotli 6.08 kB (budget ≤ 8 kB)
- lumiose-hand bundle (dist-hand/main.js, runtime and app): min 17.43 kB, gzip 6.53 kB, brotli 5.97 kB (budget ≤ 8 kB)
- solid-2 bundle (frameworks/keyed/solid-2, build-prod output): min 58.88 kB, gzip 21.54 kB, brotli 19.49 kB
- remix-v3 bundle (frameworks/keyed/remix-v3, build-prod output): min 88.27 kB, gzip 28.41 kB, brotli 25.19 kB