Benchmarks
Faster than Rust and Zig. Far ahead of Go and Bun.
Every chart is a measured result from the reports that ship with the compiler: same machine, interleaved runs, outputs checked on every run. Those reports also list where Neo is behind.
1.38× more than Rust1.45× more than Bun1.46× more than Zig2.04× more than Go
1.73× more than Rust14.3× more than Zig17.1× more than Bun22.8× more than Go
1.09× faster than Bun1.72× faster than Zig1.80× faster than Rust10.0× faster than Go
2.41× less than Rust2.84× less than Zig14.5× less than Go42.2× less than Bun
1.82× faster than Zig1.82× faster than Rust2.21× faster than Bun3.16× faster than Go
x86-64 Linux, all five languages · 2 November 2026 · method
Against Rust
Optimised Rust with serde and hyper, on x86-64 Linux.
Compute
1.83× faster than Rust
1.62× faster than Rust
1.41× faster than Rust
1.38× faster than Rust
JSON
2.00× faster than Rust
1.89× faster than Rust
1.39× faster than Rust
1.10× faster than Rust
HTTP
1.50× more than Rust
1.34× more than Rust
1.88× lower than Rust
1.35× lower than Rust
x86-64 Linux · 30–31 October 2026 · method
HTTP in depth
One executable serves with either event loop, so epoll and io_uring are compared with identical request handling. CPU per request is user plus kernel time of every server process divided by completed requests.
With four workers the load generator saturates first (servers 78–90% busy), so throughput flattens while CPU per request keeps falling.
Neo's own code costs 0.19 µs per request against Rust's 1.52 µs. The rest is kernel work every server pays, which is why HTTP is 1.3–1.5× rather than 2×.
Against Go, Bun and Rust
The same servers and JSON workload, with Go and Bun counterparts, on ARM64 Linux.
1.33× more than Rust2.31× more than Bun2.99× more than Go
1.16× more than Rust2.40× more than Go4.72× more than Bun
2.79× more than Rust18.0× more than Go82.3× more than Bun
1.76× faster than Bun2.11× faster than Rust7.46× faster than Go
3.08× less than Rust15.3× less than Go67.6× less than Bun
1.34× lower than Rust2.33× lower than Bun3.00× lower than Go
ARM64 Linux · 27 October 2026 · method
Against Zig
Release-mode Zig with std.json, std.http and http.zig, on x86-64 Linux. Each row uses the fastest Zig build and configuration measured; each HTTP server gets one vCPU, with the load generator on another core.
Compute
1.82× faster than Zig
1.51× faster than Zig
1.40× faster than Zig
1.25× faster than Zig
1.22× faster than Zig
1.14× faster than Zig
JSON
1.77× faster than Zig
1.17× faster than Zig
HTTP
1.46× more than http.zig1.86× more than std.http
1.27× more than http.zig1.50× more than std.http
1.67× more than std.http1.69× more than http.zig
2.27× lower than http.zig7.01× lower than std.http
1.21× more than std.http1.23× more than http.zig
14.1× more than std.http
1.46× lower than http.zig1.86× lower than std.http
4.69× less than http.zig22.6× less than std.http
x86-64 Linux, against Zig · 2 November 2026 · method
Raw numbers
Against Rust · x86-64 Linux
| Workload | Neo | Rust | Neo lead |
|---|---|---|---|
| N-body4,096 bodies × 10 steps · ms, lower is better | 345.3 | 633.0 | 1.83× |
| N-body1,024 bodies × 3 steps · ms, lower is better | 10.0 | 16.2 | 1.62× |
| Mandelbrot1200 × 1200, 300 iterations · ms, lower is better | 131.8 | 185.9 | 1.41× |
| Stencil1M cells × 20 passes · ms, lower is better | 33.6 | 46.5 | 1.38× |
| Workload | Neo | Rust | Neo lead |
|---|---|---|---|
| Dynamic JSON1,000-order array × 1,000, vs serde_json::Value · ms, lower is better | 175.2 | 349.9 | 2.00× |
| Dynamic JSONsmall document × 1M, vs serde_json::Value · ms, lower is better | 175.5 | 331.5 | 1.89× |
| Typed decodesmall document × 1M, vs serde derive · ms, lower is better | 122.1 | 169.2 | 1.39× |
| Typed decode1,000-order array × 1,000, vs serde derive · ms, lower is better | 87.5 | 96.5 | 1.10× |
| Workload | Neo | Rust | Neo lead |
|---|---|---|---|
| HTTP throughput2 workers, keep-alive, 64 connections · req/s | 213,863 | 142,923 | 1.50× |
| HTTP throughput1 worker, keep-alive, 64 connections · req/s | 118,817 | 88,802 | 1.34× |
| HTTP p99 latency2 workers, same load · µs, lower is better | 379 | 713 | 1.88× |
| Server CPU per request1 worker, user + kernel · µs, lower is better | 8.39 | 11.32 | 1.35× |
HTTP · x86-64 Linux
| Workers | Server | req/s | p50 µs | p99 µs | CPU/request µs |
|---|---|---|---|---|---|
| 1 | Rust (hyper) | 88,802 | 713 | 970 | 11.32 |
| 1 | Neo, epoll | 98,051 | 638 | 870 | 10.15 |
| 1 | Neo, io_uring | 118,817 | 516 | 739 | 8.39 |
| 2 | Rust (hyper) | 142,923 | 447 | 713 | 13.79 |
| 2 | Neo, epoll | 191,908 | 305 | 649 | 10.40 |
| 2 | Neo, io_uring | 213,863 | 288 | 379 | 9.34 |
| 4 | Rust (hyper) | 268,256 | 220 | 439 | 13.49 |
| 4 | Neo, epoll | 318,563 | 100 | 247 | 10.85 |
| 4 | Neo, io_uring | 309,895 | 103 | 245 | 10.13 |
Against Go, Bun and Rust · ARM64 Linux
| Workload | Neo | Rust | Go | Bun | Neo lead |
|---|---|---|---|---|---|
| HTTP throughput1 worker, hello world · req/s | 261,509 | 196,814 | 87,434 | 113,025 | 1.33×–2.99× |
| HTTP throughput4 workers, hello world · req/s | 561,581 | 485,714 | 233,903 | 118,982 | 1.16×–4.72× |
| Pipelined HTTP1 worker · req/s | 2,023,817 | 726,309 | 112,263 | 24,597 | 2.79×–82.3× |
| Dynamic JSON1M documents: build, parse, read, checksum · ms, lower is better | 229.3 | 484.3 | 1,711 | 404.3 | 1.76×–7.46× |
| Server memorypeak PSS under load, 1 worker · MiB, lower is better | 0.79 | 2.43 | 12.1 | 53.3 | 3.08×–67.6× |
| Server CPU per request1 worker, user + kernel · µs, lower is better | 3.79 | 5.05 | 11.37 | 8.80 | 1.34×–3.00× |
Against Zig · x86-64 Linux
| Workload | Neo | Zig | http.zig | std.http | Neo lead |
|---|---|---|---|---|---|
| N-body4,096 bodies × 10 steps · ms, lower is better | 377.1 | 684.7 | — | — | 1.82× |
| N-body1,024 bodies × 3 steps · ms, lower is better | 11.8 | 17.8 | — | — | 1.51× |
| Mandelbrot1200 × 1200, 300 iterations · ms, lower is better | 145.5 | 203.4 | — | — | 1.40× |
| Stencil50M cells × 20 passes · ms, lower is better | 1,421 | 1,777 | — | — | 1.25× |
| Stencil1M cells × 20 passes · ms, lower is better | 30.7 | 37.6 | — | — | 1.22× |
| Sieveprimes below 100M · ms, lower is better | 439.0 | 502.3 | — | — | 1.14× |
| Workload | Neo | Zig | http.zig | std.http | Neo lead |
|---|---|---|---|---|---|
| Dynamic JSONsmall document × 1M, vs Zig's fastest std.json variant (typed, arena) · ms, lower is better | 188.1 | 333.7 | — | — | 1.77× |
| Dynamic JSON1,000-order array × 1,000, vs Zig's fastest std.json variant (typed, arena) · ms, lower is better | 186.6 | 218.3 | — | — | 1.17× |
| Workload | Neo | Zig | http.zig | std.http | Neo lead |
|---|---|---|---|---|---|
| HTTP throughputhello world, one vCPU, 64 connections · req/s | 108,829 | — | 74,414 | 58,427 | 1.46×–1.86× |
| Rendered pageabout 5 KB of HTML built per request · req/s | 68,508 | — | 53,952 | 45,553 | 1.27×–1.50× |
| Compute per requestN-body, 256 bodies × 4 steps per POST · req/s | 1,329 | — | 786 | 796 | 1.67×–1.69× |
| p99 latencyN-body per POST, same load · µs, lower is better | 49,810 | — | 113,190 | 349,280 | 2.27×–7.01× |
| CPU-bound route32 smoothing passes over 10,000 values · req/s | 2,880 | — | 2,351 | 2,381 | 1.21×–1.23× |
| Pipelined HTTP16 requests per write (http.zig answers only the first, so it is not run) · req/s | 1,426,310 | — | — | 100,985 | 14.1× |
| Server CPU per requesthello world, user + kernel · µs, lower is better | 9.19 | — | 13.39 | 17.11 | 1.46×–1.86× |
| Server memorypeak RSS under hello-world load · MiB, lower is better | 0.80 | — | 3.73 | 18.0 | 4.69×–22.6× |
Method
x86-64 Linux · 30–31 October 2026
- Machine
- Temporary Vultr instances with dedicated AMD EPYC vCPUs: 2 vCPUs for compute and JSON (one pinned CPU per worker), 8 vCPUs for HTTP (4 for the server, 4 for the load generator).
- Software
- Ubuntu 24.04, Linux 6.8, clang 18.1.3, rustc 1.99.1 (release builds), hyper/tokio with pipeline_flush, wrk -t4 -c64.
- Procedure
- Interleaved runs on the same machine; medians of 7–30 rounds (compute), 11–15 (JSON) and 5 × 10 s after a 2 s warm-up (HTTP). Outputs are checked against each other on every run.
- Reports
RESULTS-compute-db-x86-linux-2026-10-30.mdRESULTS-http-uring-x86-linux-2026-10-31.md
ARM64 Linux · 27 October 2026
- Machine
- Ten-vCPU Linux VM on an Apple M1 Pro. One-worker cases on CPU 0; load generators on separate CPUs.
- Software
- Linux ARM64, clang 18.1.3, rustc 1.98.1, Go 1.25.14, Bun 1.3.13.
- Procedure
- Nine shuffled measured rounds after two warm-ups; five paired HTTP trials per scenario with a validating client that checks every response body.
- Reports
RESULTS-core-regression-linux-2026-10-27.md
x86-64 Linux, against Zig · 2 November 2026
- Machine
- Temporary Vultr instances with dedicated AMD EPYC-Milan vCPUs. Compute and JSON: 2 vCPUs, one pinned CPU per worker. HTTP: 4 vCPUs (2 cores); every server is confined to one vCPU with its SMT sibling idle, and wrk runs on the other core, so the server is the bottleneck.
- Software
- Ubuntu 24.04, Linux 6.8, Zig 0.17.0 ReleaseFast (baseline and -mcpu=native builds; the faster one is shown), std.json, std.http and http.zig (the better of its default and 1+1 configurations on each row), wrk -t2 -c64.
- Procedure
- Interleaved runs on the same machine; medians of 7 rounds (compute), 9 (JSON) and 11 × 10 s after a 2 s warm-up (HTTP). Outputs and responses are checked on every run. Transparent huge pages at Ubuntu's default (madvise); the 50M-cell stencil and sieve margins depend on them.
- Reports
RESULTS-zig-x86-linux-2026-11-02.md
x86-64 Linux, all five languages · 2 November 2026
- Machine
- One temporary Vultr instance with 4 dedicated AMD EPYC-Milan vCPUs (2 cores). Each HTTP server is confined to one vCPU with its SMT sibling idle and wrk runs on the other core, so the server is the bottleneck. JSON and N-body run pinned to one vCPU with every runtime on one thread.
- Software
- Ubuntu 24.04, Linux 6.8, clang 18.1.3, rustc 1.99.1 (hyper/tokio, serde_json), Go 1.25.14, Bun 1.4.4, Zig 0.17.0 ReleaseFast, wrk -t2 -c64. Each Zig bar is its fastest variant on that row: http.zig for throughput (default) and memory (1+1), std.http for pipelining (http.zig answers only the first request of a pipelined write), and std.json parsing into typed structs with an arena.
- Procedure
- All five languages in the same interleaved rounds on one machine; medians of 11 × 10 s HTTP runs after a 2 s warm-up with a fresh server per run, and of 15 rounds after 2 warm-ups for JSON and N-body. Every server passes a hello and a 16-deep pipelining check first; JSON checksums and N-body energies match on every run. Memory is the server's summed PSS, sampled every 100 ms.
- Reports
RESULTS-headline-x86-linux-2026-11-02.md
These are comparisons of specific implementations on specific workloads, not rankings of languages. Competitor programs are idiomatic release builds; every run validates outputs, and the temporary machines are destroyed afterwards.