Skip to content

Benchmarks ​

Each benchmark in benchmarks/ is one main.ts, compiled to a native binary by ChadScript and run under Node, plus a main.rs reference built with rustc -O. Before timing anything, the runner checks that all three print identical output; a benchmark that computes something different is thrown out.

binary_trees
ChadScript231 ms
Node131 ms
Rust200 ms
fib
ChadScript25 ms
Node97 ms
Rust29 ms
map_lookup
ChadScript106 ms
Node58 ms
Rust12 ms
matmul
ChadScript106 ms
Node89 ms
Rust6 ms
montecarlo
ChadScript920 ms
Node1.02 s
Rust932 ms
nbody
ChadScript125 ms
Node248 ms
Rust19 ms
sieve
ChadScript53 ms
Node113 ms
Rust10 ms
sorting
ChadScript49 ms
Node76 ms
Rust24 ms

Measured 2026-09-23 on Apple M4, macOS 26.6.2 (arm64). Node v25.3.0, Homebrew clang version 22.1.8, rustc 1.94.0 (4a4ef493e 2026-03-02). Best of 5 runs, wall clock including process startup. "vs Node" is Node's time divided by ChadScript's (above 1 means ChadScript is faster).

BenchmarkChadScriptNodeRustvs Node
binary_trees231 ms131 ms200 ms0.57x
fib25 ms97 ms29 ms3.90x
map_lookup106 ms58 ms12 ms0.55x
matmul106 ms89 ms6 ms0.85x
montecarlo920 ms1.02 s932 ms1.11x
nbody125 ms248 ms19 ms1.98x
sieve53 ms113 ms10 ms2.14x
sorting49 ms76 ms24 ms1.57x

Startup and size ​

Most of these programs finish in tens of milliseconds, so process startup is part of every number above. Measured separately for examples/shapes.ts on the same machine and date with hyperfine -N (40 runs, mean):

TimeNotes
native binary1.4 ms ± 0.2128 KB at -O2 (119 KB stripped); links only the system C library
node --import tsx examples/shapes.ts42.6 ms ± 1.2Node v25.3.0
node examples/shapes.ts45.3 ms ± 1.3Node's built-in type stripping

Reading the results ​

Rust is the ceiling, not the target: it has unboxed f64 arrays and no garbage collector. The interesting comparison is ChadScript against Node, because both implement JavaScript semantics for the same source: that difference is what ahead-of-time compilation buys.

The benchmarks that lose to Node point at known work, not general slowness:

  • map_lookup and matmul: under noUncheckedIndexedAccess every arr[i] read is typed T | undefined, and hot loops pay for handling the undefined case. Skipping that check for reads that are provably in range is the planned fix.
  • binary_trees mostly allocates short-lived objects. Node's garbage collector is generational, which suits that pattern; ChadScript's collector is new and not generational yet (planned).

Regenerating ​

sh
bun run docs/scripts/bench-page.ts      # runs scripts/bench.ts (slow), rewrites the table

The script records the machine, OS, toolchain versions and date with the numbers. Numbers from different machines are not comparable; rerun all of them together.

Next: Roadmap.