Comparison
Two ledgers. The feature matrix below is stable, hand-maintained —
features change slowly. The runtime scorecard is different: every
number in it is generated by CI, not hand-edited —
.github/workflows/benchmark.yml
runs bench/run.sh on a
GitHub-hosted runner (4 vCPU, 15 GiB RAM), builds all three runtimes in
release mode in the same run, and publishes the table straight to the job
summary. GitHub’s shared runners are weaker and noisier than dedicated
hardware, so absolute numbers vary run to run, but the ranking has held
across repeated CI runs. This page supersedes any other performance number
found elsewhere.
| Feature | Node.js 24 | Bun 1.3 | 3va |
|---|---|---|---|
| JavaScript runtime | ✓ | ✓ | ✓ |
| TypeScript (no config) | ✗ | ✓ | ✓ |
| Package manager | via npm | ✓ | ✓ |
| Process manager | via pm2 | ✗ | ✓ built-in |
| Test runner | via Jest | ✓ | ✓ Jest-compatible |
| Bundler | via webpack/esbuild | ✓ | ✓ |
| Dev server + HMR | ✗ | ✓ | ✓ |
| Deny-by-default permissions | ✗ | ✗ | ✓ |
| Post-install scripts blocked | soon¹ | partial² | ✓ always, no allowlist |
| Permission grants scoped per-dependency | ✗ | ✗ | ✓ |
| Malware + secrets audit | ✗ | ✗ | ✓ |
| OSV CVE scan (24h cache) | ✗ | ✗ | ✓ |
| CDP Debugger (--inspect) | ✓ | ✗ | ✓ |
| NAPI native addons | ✓ | ✓ | ✓ |
| WebAssembly (WASI) | partial | ✓ | ✓ |
| Post-quantum TLS (hybrid, RFC 10024) | ✗ | ✗ | ✓ client-only |
| Node.js API compat (fs/http/stream/…) | ✓ (is Node) | high, self-reported | ~97%³, self-reported |
| Platforms | Linux/macOS/Windows/Android | Linux/macOS/Windows | Linux/macOS/Windows⁴ |
| License | MIT | MIT | MIT |
| First release → latest | 2009 → 24.x | 2023 → 1.3 | v1.0.0 → 2.8 |
1 npm v12 (shipping July 2026) disables install scripts by default; npm 11 and earlier run them.
2 Bun’s trustedDependencies allowlist skips scripts for
untrusted packages, but a non-registry specifier (file:/git:/github:)
sharing a trusted package’s name could bypass it (CVE-2026-24910, fixed in
1.3.5).
3 Per-module breakdown in Roadmap — self-reported, not measured against an exhaustive conformance suite.
4 Android arm64 currently broken on main; see
Roadmap.
Runtime benchmarks — 3va vs Node.js vs Bun
| Metric | 3va | node | bun |
|---|---|---|---|
| Cold starthello world · ms ↓ | 24.1 | 24.9 | 3.9BEST |
| Cold start, TypeScriptno build step · ms ↓ | 24.9 | 65.7 | 3.9BEST |
| HTTP throughput100k req, 1k conn · req/s ↑ | 28,483 | 21,520 | 81,093BEST |
| Express 5 throughputBun's bench/express · req/s ↑ | 18,381 | 6,890 | 18,655BEST |
| p99 latencyHTTP hello world · ms ↓ | 570.65 | 56.78 | 29.1BEST |
| Peak memoryunder 100k requests · MB ↓ | 307.9 | 88.5 | 38.2BEST |
| Install a Next.js appT3 stack, warm cache · ms ↓ | 1,719 | 8,094 | 253BEST |
| Measured on GitHub Actions · 4 vCPU, 15Gi RAM, 6.17.0-1022-azure · commit 466fddc · run #35753909175 on 2026-09-22 · reproduce · test262 conformance: 96.9% (95459/98558, 0 skipped) | |||
Two methodology notes that apply to the scorecard:
- HTTP rows are measured against 3va’s HTTP server with its firewall’s
per-IP connection/rate limits raised — at the shipped defaults (100
req/s, 50 connections per source IP) a single-machine load test like this
one is mostly rejected with
403, which is the firewall working as intended, not a bug. See HTTP Performance and Load Behavior. - Install rows re-run
is-odd installwhen it’s already innode_modules(npm:npm install --silent, Bun:bun install, 3va:3va install --allow-net=registry.npmjs.org) — same package, same warm-cache condition, same CI runner, for all three.
Where Bun wins
Startup latency, raw HTTP throughput, and memory footprint, by a wide margin. 3va trades this for security guarantees Bun’s allowlist model doesn’t provide (see the CVE above) — the trade is deliberate: shaving milliseconds off startup doesn’t matter if a single spoofed dependency can exfiltrate your production secrets. A few extra milliseconds of latency is a rounding error next to the cost of a compromised supply chain — incident response, breach disclosure, and the customers who leave.
Where 3va wins
Permission grants scoped to the dependency that requested them, not the whole process; an install path with no allowlist to spoof in the first place; startup latency now roughly on par with Node.js instead of 2× slower (a 35ms → ~15–26ms fix landed in 2.5.0 — a stuck event-loop flag was spinning 100k busy iterations on every single run).
Reproduce these numbers yourself: bash bench/run.sh in the
3va repository (see bench/README.md
for methodology and caveats).