Benchmarks
Every number here comes from a result file committed in the repository (engine/ts/packages/bench/results). The current figures are from matrix-2026-10-31.json, produced by engine/ts/packages/bench/src/matrix.ts (re-run with RUNS=9 CLI_RUNS=5 node packages/bench/src/matrix.ts in engine/ts).
Machine. Intel(R) Xeon(R) Processor @ 2.10GHz, 4 logical CPUs, 16 GiB, Linux 6.18.44-fc-v185 x64, 2026-10-31. Versions. Node v22.23.4 (V8 12.4.254.21-node.57); Bun 1.4.4 (JavaScriptCore); rustc 1.97.0 (2d8144b78 2026-07-07).
Noise. A shared 4-vCPU cloud VM: other tenants share the CPUs, so individual timings vary (up to about 2x between runs on this VM). Each e2e figure is from fresh processes, original and compiled interleaved; best (min) is the most stable figure, median shows the spread. Treat differences under about 10% as noise.
Whole programs: original vs Viscosity, Node and Bun
Section titled “Whole programs: original vs Viscosity, Node and Bun”Each program’s own timed section (performance.now()), 9 fresh processes per version per runtime, original and compiled interleaved, after one discarded run of each. Compiled with the TS engine (default options); the Rust CLI’s output is compared too.
Best of 9 (median in brackets), milliseconds of each program’s timed section; speed-up = original / Viscosity.
| program | layout | Node original | Node Viscosity | Node speed-up | Bun original | Bun Viscosity | Bun speed-up |
|---|---|---|---|---|---|---|---|
| boids | fl=soa | 57.4 (68.6) | 43.8 (56.6) | 1.31× (1.21×) | 64.1 (75.4) | 34.6 (49.7) | 1.85× (1.52×) |
| heat | cells=soa | 352.4 (407.3) | 85.7 (93.6) | 4.11× (4.35×) | 96.4 (102.6) | 94.5 (118.9) | 1.02× (0.86×) |
| ledger | tx=soa | 167.5 (198.3) | 44.6 (48.7) | 3.75× (4.08×) | 117.5 (126.1) | 40.8 (52.4) | 2.88× (2.41×) |
| nbody | bs=soa | 61.6 (71.3) | 51.3 (63.5) | 1.2× (1.12×) | 50 (62.8) | 51.6 (55.3) | 0.97× (1.13×) |
| particles | ps=soa | 393 (423.3) | 90 (114) | 4.37× (3.71×) | 155.2 (178.9) | 51.7 (56.6) | 3× (3.16×) |
| geometric mean | 2.54× (2.46×) | 1.74× (1.62×) |
The original and compiled programs’ checksums matched on every run, and each program printed the same checksum on Node and on Bun. The Rust CLI’s compiled code is byte-identical to the TypeScript engine’s for every program. Bun relative to Node (geometric mean of Node best / Bun best; above 1 means Bun is faster): original programs 1.71×, compiled programs 1.17×.
Compile speed: Rust CLI vs TypeScript CLI
Section titled “Compile speed: Rust CLI vs TypeScript CLI”Method: viscosity build <file> to stdout, one fresh process per compile, 5 runs each, alternating TS and Rust. Wall time of the whole process, from Node’s child_process.
Over the 40-program corpus (sum of medians): TypeScript CLI 4764.6 ms, Rust CLI 435.8 ms, 10.9× faster. Outputs were byte-identical for every program.
In process. compile() in one Node process: 50 warm-up calls, then 200 timed calls per program. TS: the reference engine from source; Rust: @viscosity/wasm (nodejs target) on the same Node. Total of medians: TypeScript 14979.7 µs, Rust as WebAssembly 2846.8 µs, 5.26× faster.
Per-program figures are in matrix-2026-10-31.md.
Earlier: Node only (superseded)
Section titled “Earlier: Node only (superseded)”Intel(R) Xeon(R) Processor @ 2.10GHz, Node v22.23.4 (V8 12.4.254.21-node.57), 2026-10-31. Median of N fresh-process runs of each program’s own timed section. Shared cloud VM.
| program | layout chosen | original (ms) | Viscosity (ms) | speed-up |
|---|---|---|---|---|
| boids | fl=soa | 84 | 71 | 1.18× |
| heat | cells=soa | 364 | 110 | 3.3× |
| ledger | tx=soa | 237 | 46 | 5.11× |
| nbody | bs=soa | 67 | 61 | 1.09× |
| particles | ps=soa | 405 | 94 | 4.3× |
Python (CPython 3.13.18)
Section titled “Python (CPython 3.13.18)”| layout | ns per element | memory (100,000 elements) |
|---|---|---|
| dataclass objects | 26.66 | 16.0 MB |
| list columns | 43.31 | |
array('d') columns | 72.7 | 3.3 MB |
In CPython, columns save memory but cost time, so the Python plugin only transforms collections you annotate. See Python.