Benchmarks
Benchmark score in milliseconds per operation — lower is better. Every chart is the checked-in baseline from the repo’s own suites: same apps, same hardware, same run. Reproduce them with pnpm bench:all, and see benchmarks/ for what each suite measures.
Every suite at a glance
Start here: each cell is the geometric mean of that suite’s per-operation scores relative to Octane — 1× is Octane, below 1× is faster than Octane. Pick frameworks and a suite for the bar view, or scan the whole grid and re-baseline it to each suite’s fastest framework. The sections below have the full per-operation charts in milliseconds.
| suite | Octane (.tsrx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|
| js-framework | 1× | 2.6× | 2.5× | 1.1× | 1.7× | 1.1× | 1.0× |
| todomvc | 1× | 3.8× | 4.3× | 1.8× | 1.3× | 1.2× | 1.5× |
| chat-stream | 1× | 3.1× | 3.9× | 1.2× | 1.6× | 1.2× | 0.90× |
| js-framework-reorder | 1× | 2.9× | 6.3× | 1.7× | 2.2× | 1.6× | 2.1× |
| dbmon | 1× | 2.0× | 2.5× | 2.6× | 1.3× | 1.3× | 1.2× |
| effectful-list | 1× | 2.4× | 5.1× | 0.69× | 0.86× | 1.1× | 0.90× |
| memo-wall | 1× | 4.9× | 6.2× | 0.29× | 1.0× | 2.4× | 0.29× |
| recursive-context | 1× | 1.6× | 1.6× | 1.1× | 2.2× | 1.1× | 1.0× |
| signal-favoring | 1× | 7.4× | 6.3× | 0.76× | 1.1× | 0.33× | 0.40× |
| portal-swarm | 1× | 1.2× | 1.4× | 0.47× | 1.3× | 0.82× | 0.96× |
| async-waterfall | 1× | 12× | 9.4× | 0.96× | 0.96× | 0.94× | — |
| news | 1× | 1.5× | 1.2× | 0.93× | 0.51× | 0.49× | 0.63× |
| streaming-ssr | 1× | 1.4× | 1.3× | 4.5× | — | 1.3× | — |
| bundle-size | 1× | 1.0× | 0.62× | 0.76× | 0.88× | 0.84× | 0.74× |
| ssr-throughput | 1× | 3.1× | 2.8× | 1.9× | 1.2× | 1.1× | 1.1× |
| geomean | 1× | 2.7× | 2.9× | 1.1× | 1.2× | 1.0× | 0.87× |
Each cell is that framework’s score relative to Octane (1×), geometric mean across the suite’s operations. Green is faster, red is slower.
Octane vs the field
Octane compiled from .tsrx and .tsx, against React 19 (with a separate React Compiler comparison where available), Preact 10, Solid, Svelte 5, Ripple and Vue Vapor — each framework’s fixture written the way its docs recommend. The ranked chips on each card are that suite’s one-line reading: every framework’s geometric mean across the card’s operations, relative to Octane, fastest first.
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 8 iterations)
| operation | Octane (.tsrx) | Octane (.tsx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|---|
| run | 2.2 | 2.2 | 5.7 | 7.9 | 2.2 | 3.8 | 2.4 | 2.8 |
| replace | 4.8 | 5.0 | 9.7 | 13 | 5.6 | 7.4 | 5.2 | 5.4 |
| add | 1.7 | 1.7 | 4.7 | 6.7 | 1.8 | 3.1 | 1.9 | 2.0 |
| update | 0.38 | 0.34 | 1.1 | 1.5 | 1.1 | 0.72 | 0.58 | 0.46 |
| select | 0.12 | 0.16 | 0.64 | 1.1 | 0.14 | 0.16 | 0.10 | 0.04 |
| swap | 0.46 | 0.44 | 4.6 | 0.88 | 0.46 | 0.80 | 0.74 | 0.56 |
| remove | 0.24 | 0.18 | 0.62 | 0.70 | 0.16 | 0.50 | 0.22 | 0.22 |
| runlots | 13 | 14 | 116 | 53 | 14 | 24 | 14 | 17 |
| clear | 20 | 22 | 46 | 32 | 22 | 25 | 24 | 21 |
| nodes_1k | 10074 | 10074 | 10072 | 10072 | 10072 | 10116 | 10074 | 10072 |
| elements_1k | 8051 | 8051 | 8051 | 8051 | 8051 | 8051 | 8051 | 8050 |
| text_1k | 2021 | 2021 | 2021 | 2021 | 2021 | 2045 | 2023 | 2022 |
| comments_1k | 2.0 | 2.0 | 0 | 0 | 0 | 20 | 0 | 0 |
| empty_text_1k | 0 | 0 | 0 | 0 | 0 | 2.0 | 2.0 | 1.0 |
| whitespace_text_1k | 0 | 0 | 0 | 0 | 0 | 22 | 0 | 0 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 8 iterations)
| operation | Octane (.tsrx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|
| add 100 | 2.5 | 13 | 17 | 1.1 | 2.2 | 1.8 | 2.3 |
| toggle all on | 0.16 | 0.42 | 0.50 | 1.2 | 0.28 | 0.32 | 0.40 |
| toggle all off | 0.16 | 0.42 | 0.50 | 0.88 | 0.28 | 0.28 | 0.38 |
| complete 25 | 0.98 | 6.1 | 6.6 | 1.1 | 0.72 | 0.88 | 0.84 |
| filter cycle | 0.74 | 1.2 | 1.3 | 0.98 | 0.98 | 0.96 | 1.3 |
| edit 10 | 0.78 | 5.1 | 7.6 | 1.8 | 2.3 | 1.1 | 1.7 |
| clear completed | 0.24 | 0.50 | 0.42 | 0.40 | 0.20 | 0.26 | 0.38 |
| destroy 25 | 0.72 | 5.8 | 6.0 | 0.84 | 0.96 | 0.66 | 0.76 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 8 iterations)
| operation | Octane (.tsrx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|
| fine stream | 1.6 | 6.8 | 8.1 | 2.7 | 2.8 | 1.5 | 1.00 |
| coarse stream | 0.42 | 1.3 | 2.5 | 0.70 | 0.84 | 0.66 | 0.60 |
| append history | 1.2 | 5.4 | 10 | 1.1 | 2.1 | 1.5 | 0.98 |
| switch conversation | 2.6 | 3.2 | 3.3 | 4.5 | 6.0 | 4.0 | 4.4 |
| type 160 chars | 1.1 | 4.3 | 3.3 | 0.50 | 0.84 | 0.94 | 0.56 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 8 iterations)
| operation | Octane (.tsrx) | Octane (.tsx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|---|
| reverse | 1.0 | 0.97 | 1.9 | 2.0 | 1.0 | 15 | 0.97 | 1.3 |
| shuffle | 1.3 | 1.3 | 1.9 | 2.8 | 1.3 | 1.8 | 1.3 | 1.5 |
| rotatef | 0.08 | 0.10 | 1.5 | 0.21 | 0.15 | 0.18 | 0.13 | 0.74 |
| rotateb | 0.07 | 0.08 | 0.16 | 0.20 | 0.14 | 0.11 | 0.11 | 0.20 |
| prepend100 | 0.34 | 0.30 | 1.1 | 1.4 | 0.32 | 0.64 | — | 0.30 |
| append100 | 0.30 | 0.30 | 0.78 | 1.3 | 0.32 | 0.60 | 0.42 | 0.38 |
| insertmid100 | 0.34 | 0.30 | 0.92 | 1.4 | 0.36 | 0.74 | — | 0.34 |
| removefirst | 0.02 | 0.04 | 0.14 | 0.20 | 0.07 | 0.11 | 0.06 | 0.03 |
| removeevery10 | 0.12 | 0.16 | 0.26 | 0.30 | 0.17 | 0.18 | 0.16 | 0.20 |
| displace3 | 0.06 | 0.10 | 0.15 | 1.3 | 0.14 | 0.11 | 0.13 | 0.21 |
| displace4 | 0.07 | 0.10 | 0.15 | 1.3 | 0.16 | 0.12 | 0.12 | 0.21 |
| displace5 | 0.07 | 0.10 | 0.16 | 1.3 | 0.16 | 0.12 | 0.11 | 0.20 |
| displace6 | 0.07 | 0.09 | 0.16 | 1.3 | 0.15 | 0.12 | 0.12 | 0.22 |
| displace8 | 0.08 | 0.11 | 0.17 | 1.3 | 0.16 | 0.12 | 0.11 | 0.22 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 30 iterations)
| operation | Octane (.tsrx) | Octane (.tsx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|---|
| mount | 3.7 | 4.0 | 7.0 | 8.6 | 14 | 5.3 | 6.2 | 5.2 |
| tick | 1.5 | 1.5 | 2.5 | 3.8 | 8.7 | 2.2 | 2.1 | 1.7 |
| tick_partial | 0.46 | 0.52 | 1.4 | 2.5 | 1.3 | 0.68 | 0.65 | 0.54 |
| remount | 4.2 | 4.5 | 7.8 | 9.8 | 10 | 4.9 | 4.5 | 4.2 |
| sort | 2.3 | 2.5 | 4.7 | 5.4 | 2.9 | 3.0 | 2.4 | 2.5 |
| unmount | 1.7 | 1.9 | 2.8 | 2.4 | 2.9 | 1.8 | 1.8 | 1.9 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 30 iterations)
| operation | Octane (.tsrx) | Octane (.tsx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|---|
| mount_1k | 8.3 | 8.7 | 10 | 13 | 9.3 | 9.9 | 9.7 | 11 |
| update_nodeps | 0.09 | 0.13 | 0.89 | 7.4 | 0.00 | 0.01 | 0.07 | 0.00 |
| update_deps | 2.2 | 2.4 | 3.1 | 7.7 | 2.7 | 2.6 | 2.6 | 2.7 |
| clear | 1.0 | 1.0 | 1.6 | 1.9 | 1.5 | 1.3 | 1.3 | 1.9 |
| remount | 9.4 | 9.6 | 12 | 15 | 11 | 11 | 11 | 13 |
| remove_100_scattered | 0.33 | 0.37 | 1.7 | 4.7 | 0.86 | 0.48 | 0.45 | 1.0 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 20 iterations)
| operation | Octane (.tsrx) | Octane (.tsx) | React 19 | React Compiler 1.0 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|---|---|
| mount | 13 | 16 | 12 | 12 | 16 | 11 | 12 | 12 | 16 |
| parent_rerender_equal_A | 0.00 | 0.10 | 0.15 | 0.00 | 0.21 | 0.00 | 0.01 | 0.07 | 0.00 |
| parent_rerender_equal_B | 0.25 | 0.32 | 0.18 | 0.00 | 0.23 | 0.00 | 0.01 | 0.08 | 0.00 |
| one_change_A | 0.00 | 0.10 | 0.17 | 0.16 | 0.22 | 0.02 | 0.05 | 0.10 | 0.02 |
| one_change_B | 0.25 | 0.33 | 0.21 | 0.21 | 0.25 | 0.02 | 0.05 | 0.10 | 0.02 |
| ctx_through_wall_A | 0.35 | 0.77 | 0.99 | 0.83 | 1.2 | 0.30 | 0.40 | 0.41 | 0.25 |
| ctx_through_wall_B | 0.64 | 1.0 | 1.0 | 0.83 | 1.3 | 0.30 | 0.40 | 0.37 | 0.26 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 20 iterations)
| operation | Octane (.tsrx) | Octane (.tsx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|---|
| mount | 4.2 | 7.0 | 5.2 | 4.6 | 4.5 | 15 | 5.2 | 11 |
| update_root | 0.54 | 1.2 | 0.65 | 1.2 | 0.54 | 0.54 | 0.55 | 0.34 |
| update_partial | 0.05 | 0.11 | 0.09 | 0.07 | 0.04 | 0.09 | 0.02 | 0.04 |
| partial_unmount | 0.04 | 0.04 | 0.09 | 0.05 | 0.04 | 0.09 | 0.04 | 0.01 |
| partial_remount | 0.06 | 0.11 | 0.11 | 0.14 | 0.15 | 0.35 | 0.20 | 0.14 |
| unmount | 0.52 | 2.1 | 0.75 | 0.99 | 0.48 | 0.79 | 0.37 | 0.66 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 20 iterations)
| operation | Octane (.tsrx) | Octane (.tsx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|---|
| mount | 1.4 | 1.9 | 2.8 | 1.5 | 1.8 | 1.7 | 1.9 | 1.8 |
| bump_shallow | 0.00 | 0.02 | 0.05 | 0.05 | 0.00 | 0.00 | 0.00 | 0.00 |
| bump_middle | 0.00 | 0.01 | 0.05 | 0.03 | 0.00 | 0.00 | 0.00 | 0.00 |
| bump_deep | 0.00 | 0.00 | 0.05 | 0.01 | 0.00 | 0.00 | 0.00 | 0.00 |
| bump_sweep | 0.03 | 0.08 | 0.40 | 0.23 | 0.01 | 0.02 | 0.01 | 0.01 |
| bump_sweep_batched | 0.01 | 0.03 | 0.06 | 0.23 | 0.01 | 0.01 | 0.00 | 0.00 |
| bump_sweep_reverse | 0.01 | 0.03 | 0.07 | 0.20 | 0.01 | 0.01 | 0.00 | 0.00 |
| unmount | 0.16 | 0.15 | 0.15 | 0.15 | 0.11 | 0.15 | 0.14 | 0.11 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 20 iterations)
| operation | Octane (.tsrx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|
| mount_closed | 2.5 | 4.1 | 3.1 | 4.6 | 4.4 | 2.3 | 4.4 |
| open_all | 1.3 | 1.4 | 3.4 | 1.2 | 2.8 | 3.1 | 2.1 |
| rerender_open_A | 0.03 | 0.28 | 0.50 | 0.00 | 0.01 | 0.03 | 0 |
| rerender_open_B | 0.26 | 0.30 | 0.49 | 0.00 | 0.01 | 0.03 | 0.00 |
| rerender_open_B_stable | 0.23 | 0.17 | 0.25 | 0.00 | 0.01 | 0.03 | 0 |
| open_close_cycle | 1.5 | 1.8 | 3.8 | 1.3 | 3.1 | 2.4 | 2.4 |
| open_close_distinct | 1.8 | 2.1 | 3.7 | 1.3 | 3.1 | 2.6 | 2.4 |
| dispatch_through_portal | 0.00 | 0.01 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 |
| nodes_closed_main | 2622 | 2014 | 2014 | 2614 | 3228 | 2619 | 2618 |
| elements_closed_main | 1411 | 1411 | 1411 | 1411 | 1411 | 1411 | 1411 |
| text_closed_main | 603 | 603 | 603 | 1203 | 1214 | 608 | 1207 |
| comments_closed_main | 608 | 0 | 0 | 0 | 603 | 600 | 0 |
| nodes_open_main | 2822 | 2214 | 2214 | 2614 | 4828 | 2619 | 3818 |
| comments_open_main | 608 | 0 | 0 | 0 | 1403 | 600 | 0 |
| nodes_open_body | 7025 | 5217 | 5217 | 5617 | 8431 | 6222 | 8021 |
| elements_open_body | 3412 | 3412 | 3412 | 3212 | 3412 | 3212 | 3212 |
| text_open_body | 1805 | 1805 | 1805 | 2405 | 3616 | 2410 | 4809 |
| comments_open_body | 1808 | 0 | 0 | 0 | 1403 | 600 | 0 |
| empty_text_open_body | 0 | 0 | 0 | 600 | 605 | 605 | 3004 |
| whitespace_text_open_body | 2.0 | 2.0 | 2.0 | 2.0 | 1208 | 2.0 | 2.0 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 10 iterations)
| operation | Octane (.tsrx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 |
|---|---|---|---|---|---|---|
| init | 19 | 304 | 175 | 18 | 19 | 18 |
| update | 18 | 177 | 177 | 18 | 18 | 17 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 20 iterations)
| operation | Octane (.tsrx) | Octane (.tsx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|---|
| SSR render | 0.06 | 0.05 | 0.08 | 0.07 | 0.04 | 0.02 | 0.02 | 0.02 |
| hydrate | 1.5 | 1.7 | 2.5 | 1.8 | 1.8 | 1.5 | 1.1 | 1.7 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 30 iterations)
| operation | Octane (.tsrx) | React 19 | Preact 10 | Solid 2.0 beta | Ripple 0.3 |
|---|---|---|---|---|---|
| staggered shell | 0.19 | 0.43 | 0.55 | 2.3 | 0.44 |
| staggered complete | 51 | 51 | 52 | 51 | 51 |
| all-fast shell | 0.09 | 0.13 | 0.09 | 1.8 | 0.08 |
| all-fast complete | 1.2 | 1.4 | 1.2 | 1.9 | 1.4 |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (production build bytes)
| operation | Octane (.tsrx) | Octane (.tsx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|---|
| rows total gzip | 18 kB | 33 kB | 61 kB | 10 kB | 14 kB | 18 kB | 13 kB | — |
| rows app gzip | 2 kB | 3 kB | 2 kB | 2 kB | 2 kB | 2 kB | 2 kB | — |
| Todo app gzip | 2 kB | — | 1 kB | 983 B | 1 kB | 1 kB | 2 kB | 1 kB |
| chat app gzip | 3 kB | — | 2 kB | 2 kB | 2 kB | 2 kB | 2 kB | 2 kB |
geometric mean across all operations, × vs Octane (.tsrx) — lower is better
Data table (score ms, 10 iterations)
| operation | Octane (.tsrx) | React 19 | Preact 10 | Solid 2.0 beta | Svelte 5 | Ripple 0.3 | Vue Vapor 3.6 beta |
|---|---|---|---|---|---|---|---|
| news-50 | 0.03 | 0.10 | 0.09 | 0.06 | 0.04 | 0.03 | 0.04 |
| news-500 | 0.37 | 1.1 | 1.0 | 0.67 | 0.42 | 0.43 | 0.40 |
The authoring cliff
Octane against itself: what naively-authored code costs relative to the compiled fast path. The de-opt fixtures render the same apps through plain createElement — the shape every binding produces — so the cliff is a first-class, regression-guarded number.
geometric mean across all operations, × vs Tuned .tsrx — lower is better
Data table (score ms, 8 iterations)
| operation | Tuned .tsrx | Naive .tsrx (React-style) | Naive .tsx | Plain .ts createElement |
|---|---|---|---|---|
| run | 2.2 | 2.7 | 2.8 | 5.4 |
| replace | 4.9 | 5.4 | 5.1 | 9.0 |
| add | 1.8 | 2.3 | 2.3 | 7.7 |
| update | 0.46 | 0.56 | 0.60 | 5.5 |
| select | 0.12 | 0.12 | 0.18 | 0.14 |
| swap | 0.54 | 0.84 | 0.68 | 7.8 |
| remove | 0.28 | 0.36 | 0.46 | 4.0 |
| runlots | 13 | 16 | 17 | 35 |
| clear | 20 | 19 | 20 | 35 |
| nodes_1k | 10074 | 10074 | 10074 | 10072 |
| elements_1k | 8051 | 8051 | 8051 | 8051 |
| text_1k | 2021 | 2021 | 2021 | 2021 |
| comments_1k | 2.0 | 2.0 | 2.0 | 0 |
| empty_text_1k | 0 | 0 | 0 | 0 |
| whitespace_text_1k | 0 | 0 | 0 | 0 |
geometric mean across all operations, × vs Compiled .tsrx — lower is better
Data table (score ms, 30 iterations)
| operation | Compiled .tsrx | Plain .ts createElement |
|---|---|---|
| mount | 3.6 | 6.8 |
| tick | 1.4 | 5.1 |
| tick_partial | 0.46 | 4.0 |
| remount | 4.1 | 7.1 |
| sort | 2.2 | 6.8 |
| unmount | 1.7 | 2.6 |
Data table (score ms, 10 iterations)
| operation | Octane SSR |
|---|---|
| waterfall depth 1 | 0.04 |
| waterfall depth 2 | 0.04 |
| waterfall depth 4 | 0.06 |
| depth 4 × 32 wide | 2.0 |
| escape-heavy page | 3.3 |
| de-opt page (fast) | 0.48 |
| de-opt page (de-opted) | 1.3 |