Benchmarks
How PraxisJS compares to Solid, Svelte, Vue, Lit, Preact and React in js-framework-benchmark, with the full results table and methodology.
Benchmarks
PraxisJS is measured with js-framework-benchmark, the standard suite for comparing frontend frameworks. Every entry renders the same table of rows and runs the same operations in Chrome. Results below are from the keyed table: rows keep their identity, so a moved row is moved, not rewritten.
How to read this
- Lower is better. Every number is the median of the measured runs.
- Total time is mostly the browser. A benchmark's duration runs from the click to the end of the next paint. Most of it is style, layout and paint, which costs the same for every framework that produces the same DOM. Framework differences live in the remaining few milliseconds, so small gaps in total time are real gaps in framework work.
- vanillajs is hand-written DOM code, written for this benchmark only. It is the reference for what the browser alone costs, not a framework you would build an app with. It can be beaten when a framework does less DOM work than the hand-written version.
- Slowdown (
1.05x) is a framework's time divided by the fastest entry in that benchmark. The overall score is the geometric mean of those slowdowns.
Results
| Benchmark | vanillajs hand-written | PraxisJS runtime 0.8.0 | Solid 1.9.3 | Svelte 5.42.1 | Vue 3.5.39 | Lit 3.2.0 | Preact + signals 11 | React hooks 19.2 |
|---|---|---|---|---|---|---|---|---|
create 1k ms | 24.2 1.00x | 24.3 1.00x | 26.9 1.11x | 26.1 1.08x | 28.2 1.17x | 28.5 1.18x | 32.3 1.33x | 28.4 1.17x |
replace 1k ms | 25.6 1.00x | 27.2 1.06x | 28.4 1.11x | 28.9 1.13x | 32.2 1.26x | 30.8 1.20x | 41.0 1.60x | 34.5 1.35x |
update every 10th ms | 14.0 1.03x | 13.6 1.00x | 17.5 1.29x | 15.7 1.15x | 17.6 1.29x | 16.0 1.18x | 14.9 1.10x | 20.3 1.49x |
select row ms | 4.5 1.15x | 3.9 1.00x | 4.6 1.18x | 7.3 1.87x | 5.6 1.44x | 8.2 2.10x | 5.8 1.49x | 8.1 2.08x |
swap rows ms | 15.9 1.01x | 15.7 1.00x | 17.3 1.10x | 17.9 1.14x | 18.3 1.17x | 22.0 1.40x | 20.7 1.32x | 117.1 7.46x |
remove row ms | 13.4 1.00x | 13.7 1.02x | 14.7 1.10x | 14.2 1.06x | 16.9 1.26x | 15.4 1.15x | 14.7 1.10x | 15.8 1.18x |
create 10k ms | 250.5 1.00x | 258.7 1.03x | 271.8 1.09x | 273.9 1.09x | 300.2 1.20x | 293.2 1.17x | 350.7 1.40x | 444.6 1.77x |
append 1k ms | 28.1 1.00x | 29.0 1.03x | 30.5 1.09x | 30.1 1.07x | 32.8 1.17x | 34.0 1.21x | 38.4 1.37x | 34.2 1.22x |
clear ms | 11.6 1.00x | 12.6 1.09x | 14.7 1.27x | 14.1 1.22x | 17.8 1.53x | 18.1 1.56x | 19.9 1.72x | 22.6 1.95x |
| geometric mean | 1.02 | 1.03 | 1.14 | 1.18 | 1.27 | 1.32 | 1.37 | 1.78 |
| Benchmark | vanillajs hand-written | PraxisJS runtime 0.8.0 | Solid 1.9.3 | Svelte 5.42.1 | Vue 3.5.39 | Lit 3.2.0 | Preact + signals 11 | React hooks 19.2 |
|---|---|---|---|---|---|---|---|---|
ready memory MB | 0.6 1.00x | 0.7 1.23x | 0.6 1.07x | 0.7 1.18x | 0.9 1.55x | 0.7 1.27x | 0.7 1.23x | 1.2 2.11x |
run memory MB | 1.9 1.00x | 2.7 1.46x | 2.7 1.43x | 2.9 1.54x | 3.9 2.08x | 2.8 1.50x | 4.9 2.62x | 4.4 2.35x |
create/clear 1k x5 MB | 0.6 1.00x | 0.9 1.44x | 0.8 1.20x | 1.0 1.53x | 1.2 1.86x | 0.9 1.38x | 9.0 14.03x | 2.0 3.09x |
| Benchmark | vanillajs hand-written | PraxisJS runtime 0.8.0 | Solid 1.9.3 | Svelte 5.42.1 | Vue 3.5.39 | Lit 3.2.0 | Preact + signals 11 | React hooks 19.2 |
|---|---|---|---|---|---|---|---|---|
uncompressed size kB | 11.3 1.00x | 31.2 2.76x | 11.5 1.02x | 26.6 2.35x | 64.3 5.69x | 22.1 1.96x | 23.3 2.06x | 190.3 16.84x |
compressed size kB | 2.5 1.00x | 10.3 4.12x | 4.5 1.80x | 9.7 3.88x | 23.3 9.32x | 7.3 2.92x | 8.3 3.32x | 51.4 20.56x |
first paint ms | 61.8 1.02x | 81.5 1.35x | 60.4 1.00x | 86.8 1.44x | 122.2 2.02x | 70.7 1.17x | 78.4 1.30x | 278.5 4.61x |
PraxisJS is not first on memory and size: it holds a little more memory than Solid, and its runtime (signals, decorators, components, keyed lists) ships more JavaScript than Solid's or Svelte's. First paint is ahead of Svelte, Vue and React, and behind Solid, Lit and Preact.
Script time
Script time is the JavaScript part of a benchmark: the framework's own work, without layout and paint.
| Script time (ms) | PraxisJS | Solid | Svelte | Vue | Lit | Preact + signals | React hooks | vanillajs |
|---|---|---|---|---|---|---|---|---|
| create 1k | 2.7 | 3.1 | 3.5 | 6.0 | 5.3 | 10.7 | 6.3 | 2.0 |
| replace 1k | 5.0 | 6.0 | 7.1 | 9.7 | 8.4 | 19.2 | 12.6 | 3.9 |
| update every 10th | 0.9 | 1.7 | 2.0 | 3.3 | 2.2 | 1.5 | 5.4 | 0.7 |
| select row | 0.7 | 1.2 | 3.5 | 2.0 | 3.4 | 2.4 | 3.8 | 0.6 |
| swap rows | 0.6 | 1.5 | 2.0 | 2.2 | 2.3 | 3.8 | 24.1 | 0.1 |
| remove row | 0.5 | 0.6 | 0.9 | 3.0 | 1.2 | 1.4 | 1.7 | 0.5 |
| create 10k | 25.5 | 26.9 | 29.4 | 46.9 | 45.1 | 98.6 | 196.7 | 19.2 |
| append 1k | 2.9 | 3.5 | 3.7 | 6.1 | 5.9 | 11.2 | 7.7 | 2.0 |
| clear | 10.1 | 11.7 | 11.6 | 14.8 | 15.3 | 17.0 | 20.0 | 9.1 |
The runner starts the V8 CPU profiler and forces a full garbage collection right before each measured click. Code then runs colder than in a normal page, so script times are higher than what you would measure by hand. The conditions are the same for every framework.
Methodology
- Date
- October 16, 2026
- Suite
- js-framework-benchmark, keyed table
- Browser
- Chrome 155, visible window
- Machine
- Apple M3 Pro, macOS 27
- Iterations
- 15 per benchmark, median reported
- Run
- PraxisJS 0.8 from npm
- Each benchmark runs on a fresh page after warm-up runs. The suite slows the CPU down for some operations, the same way for every framework.
- Every entry is the suite's own app for that framework, built for production. The PraxisJS entry is plain idiomatic code: a component with
@Statefields, rows as stores with an@State() label,Forfor the list and@Selectorfor the selected row. - All frameworks run in the same session on the same machine.
- Upstream suite: krausest/js-framework-benchmark
- PraxisJS entry and raw results: the
praxisjs-benchmarkrepository, a clone of the suite with aframeworks/keyed/praxisjsentry and apraxisjs-report/folder