Skip to content

bun: declare the endpoints in Bun.serve routes instead of branching on req.url - #1282

Merged
MDA2AV merged 2 commits into
MDA2AV:mainfrom
nigrosimone:bun-routes
Aug 23, 2026
Merged

bun: declare the endpoints in Bun.serve routes instead of branching on req.url#1282
MDA2AV merged 2 commits into
MDA2AV:mainfrom
nigrosimone:bun-routes

Conversation

@nigrosimone

@nigrosimone nigrosimone commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Bun.serve has had a routes option since 1.2.3 and this entry runs 1.4, but it does not use it: fetch receives everything and the handler branches on req.url with a chain of ifs. This declares the endpoints in routes instead, so the router matches method and path and fills in req.params. fetch stays as the 404.

I should say where this comes from, because it looks bad otherwise. I wrote that first implementation myself in #1163 on 15 August, when completeness did not exist and not using the router cost nothing. Completeness arrived on 21 August in #1223 and the entry has carried routing: false since, which is an accurate description of my code and takes 2.5% off its composite, about 23 points on the published numbers. So a choice that was free when I made it now costs points to a framework that competes with mine, and I would rather fix it than leave it there to be read as me having favoured my own entry.

It is not a trade. Measured locally on the baseline shape with bun 1.3.14, alternating rounds: the chain of ifs 2,812 req/s, routes 2,832. The router is free here, so the 2.5% is a straight gain.

Every endpoint answers what it answered before, checked request by request against the previous build: the three baseline shapes, json with and without gzip, upload, static with identity and br, the missing file, the traversal guard, async-db, fortunes and the four crud verbs. One difference, on a method nobody sends: DELETE /baseline11 now gets 404 rather than being answered as a GET. Neither validate.sh nor the profile sends it.

completeness.routing goes to true with it.

Ref #1283

@nigrosimone
nigrosimone marked this pull request as ready for review August 23, 2026 06:06
@MDA2AV

MDA2AV commented Aug 23, 2026

Copy link
Copy Markdown
Owner

/benchmark --save

@github-actions

Copy link
Copy Markdown
Contributor

👋 Benchmark request received. A collaborator will review and approve the run.

@github-actions

Copy link
Copy Markdown
Contributor

Benchmark Results

Framework: bun | Test: all tests

Test Conn RPS CPU Mem Δ RPS Δ Mem
baseline 512 1,806,113 6742.0% 1.3GiB +1.7% ~0%
baseline 4096 1,933,399 6739.6% 1.2GiB +1.3% ~0%
pipelined 512 90,898 1867.8% 550MiB +1.7% -33.4%
pipelined 4096 346,547 6593.0% 863MiB +1.9% +24.5%
limited-conn 512 1,394,461 6215.0% 1.1GiB +0.8% ~0%
limited-conn 4096 1,649,543 6410.1% 1.2GiB +0.7% +9.1%
json 4096 1,119,942 6511.8% 1.1GiB +0.1% +11.3%
json-comp 512 430,945 6064.4% 1.1GiB ~0% ~0%
json-comp 4096 463,429 6467.9% 1.1GiB -0.3% ~0%
json-comp 16384 466,635 6527.8% 1.2GiB -0.5% ~0%
json-tls 4096 1,076,199 6320.6% 1.0GiB -1.1% ~0%
upload 32 1,913 3069.7% 2.4GiB +0.2% ~0%
upload 256 1,988 5862.1% 2.6GiB -0.4% ~0%
api-4 256 43,637 393.3% 156MiB -0.8% -1.3%
api-16 1024 152,696 1494.5% 595MiB -0.9% +0.2%
static 1024 573,475 6592.1% 1.1GiB +0.4% -8.3%
static 4096 570,062 6581.8% 1.1GiB +0.6% -8.3%
static 6800 560,918 6565.4% 1.2GiB +0.9% ~0%
static-tls 1024 484,123 6559.5% 1.1GiB -1.5% -8.3%
static-tls 4096 472,364 6478.5% 1.1GiB -0.4% -8.3%
static-tls 6800 461,360 6388.3% 1.2GiB -0.5% ~0%
async-db 1024 277,270 5156.2% 2.2GiB -0.5% +4.8%
crud 4096 312,418 2841.3% 1.5GiB +0.7% ~0%
fortunes 1024 83,251 6392.8% 2.0GiB -0.2% ~0%
Full log
[info] CPU 4775.9% | Mem 1.9GiB

=== Best: 277270 req/s (CPU: 5156.2%, Mem: 2.2GiB) ===
[info] input BW: 18.51MB/s (avg template: 70 bytes)
[info] saved results/async-db/1024/bun.json
httparena-bench-bun
httparena-bench-bun

==============================================
=== bun / crud / 4096c (tool=gcannon) ===
==============================================
[info] resetting postgres for a clean per-profile baseline
[info] starting postgres sidecar
httparena-postgres
[info] postgres ready (seeded)
[info] waiting for server...
[info] server ready

[run 1/3]
gcannon v0.5.3
  Target:    localhost:8080/
  Threads:   64
  Conns:     4096 (64/thread)
  Pipeline:  1
  Req/conn:  200
  Templates: 20
  Expected:  200
  Duration:  15s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   13.30ms   13.60ms   17.50ms   25.60ms   38.20ms

  4597227 requests in 15.00s, 4597035 responses
  Throughput: 306.43K req/s
  Bandwidth:  103.46MB/s
  Status codes: 2xx=4597035, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 4597035 / 4597035 responses (100.0%)
  Reconnects: 21567
  Per-template: 254549,280750,271775,241433,241863,238011,209079,208686,208892,208482,208229,208774,208973,208302,208363,208657,243877,247198,246092,245050
  Per-template-ok: 254549,280750,271775,241433,241863,238011,209079,208686,208892,208482,208229,208774,208973,208302,208363,208657,243877,247198,246092,245050
[info] CPU 3002.1% | Mem 1.6GiB

[run 2/3]
gcannon v0.5.3
  Target:    localhost:8080/
  Threads:   64
  Conns:     4096 (64/thread)
  Pipeline:  1
  Req/conn:  200
  Templates: 20
  Expected:  200
  Duration:  15s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   13.00ms   13.50ms   17.00ms   24.00ms   40.10ms

  4686279 requests in 15.00s, 4686279 responses
  Throughput: 312.37K req/s
  Bandwidth:  104.65MB/s
  Status codes: 2xx=4686279, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 4686264 / 4686279 responses (100.0%)
  Reconnects: 22662
  Per-template: 274696,285124,285309,246102,245529,246099,212648,211360,211743,211648,211580,211430,211072,211334,211697,211484,240765,249189,249014,248441
  Per-template-ok: 274696,285124,285309,246102,245529,246099,212648,211360,211743,211648,211580,211430,211072,211334,211697,211484,240765,249189,249014,248441
[info] CPU 2841.3% | Mem 1.5GiB

[run 3/3]
gcannon v0.5.3
  Target:    localhost:8080/
  Threads:   64
  Conns:     4096 (64/thread)
  Pipeline:  1
  Req/conn:  200
  Templates: 20
  Expected:  200
  Duration:  15s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   13.07ms   13.50ms   17.30ms   25.60ms   41.50ms

  4665106 requests in 15.00s, 4665106 responses
  Throughput: 310.95K req/s
  Bandwidth:  104.19MB/s
  Status codes: 2xx=4665106, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 4665101 / 4665106 responses (100.0%)
  Reconnects: 22550
  Per-template: 275261,283686,281912,244679,245232,245766,212159,210934,211335,211206,210814,211120,211151,210356,209511,209173,239773,247404,247893,245736
  Per-template-ok: 275261,283686,281912,244679,245232,245766,212159,210934,211335,211206,210814,211120,211151,210356,209511,209173,239773,247404,247893,245736
[info] CPU 2935.5% | Mem 1.5GiB

=== Best: 312418 req/s (CPU: 2841.3%, Mem: 1.5GiB) ===
[info] input BW: 26.82MB/s (avg template: 90 bytes)
[info] saved results/crud/4096/bun.json
httparena-bench-bun
httparena-bench-bun

==============================================
=== bun / fortunes / 1024c (tool=gcannon) ===
==============================================
[info] resetting postgres for a clean per-profile baseline
[info] starting postgres sidecar
httparena-postgres
[info] postgres ready (seeded)
[info] waiting for server...
[info] server ready

[run 1/3]
gcannon v0.5.3
  Target:    localhost:8080/fortunes
  Threads:   64
  Conns:     1024 (16/thread)
  Pipeline:  1
  Req/conn:  unlimited (keep-alive)
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   9.31ms   8.58ms   15.60ms   24.40ms   41.00ms

  409053 requests in 5.00s, 409053 responses
  Throughput: 81.77K req/s
  Bandwidth:  1.89GB/s
  Status codes: 2xx=409053, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 409052 / 409053 responses (100.0%)
[info] CPU 6275.9% | Mem 2.0GiB

[run 2/3]
gcannon v0.5.3
  Target:    localhost:8080/fortunes
  Threads:   64
  Conns:     1024 (16/thread)
  Pipeline:  1
  Req/conn:  unlimited (keep-alive)
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   9.10ms   8.47ms   15.10ms   22.20ms   28.20ms

  415072 requests in 5.00s, 415072 responses
  Throughput: 82.98K req/s
  Bandwidth:  1.92GB/s
  Status codes: 2xx=415072, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 415067 / 415072 responses (100.0%)
[info] CPU 6454.2% | Mem 2.0GiB

[run 3/3]
gcannon v0.5.3
  Target:    localhost:8080/fortunes
  Threads:   64
  Conns:     1024 (16/thread)
  Pipeline:  1
  Req/conn:  unlimited (keep-alive)
  Expected:  200
  Duration:  5s


  Thread Stats   Avg      p50      p90      p99    p99.9
    Latency   8.81ms   8.10ms   14.90ms   22.00ms   28.00ms

  416257 requests in 5.00s, 416257 responses
  Throughput: 83.22K req/s
  Bandwidth:  1.92GB/s
  Status codes: 2xx=416257, 3xx=0, 4xx=0, 5xx=0
  Latency samples: 416256 / 416257 responses (100.0%)
[info] CPU 6392.8% | Mem 2.0GiB

=== Best: 83251 req/s (CPU: 6392.8%, Mem: 2.0GiB) ===
[info] saved results/fortunes/1024/bun.json
httparena-bench-bun
httparena-bench-bun
[info] skip: bun does not subscribe to baseline-h2
[info] skip: bun does not subscribe to static-h2
[info] skip: bun does not subscribe to baseline-h2c
[info] skip: bun does not subscribe to json-h2c
[info] skip: bun does not subscribe to baseline-h3
[info] skip: bun does not subscribe to static-h3
[info] skip: bun does not subscribe to gateway-64
[info] skip: bun does not subscribe to gateway-h3
[info] skip: bun does not subscribe to production-stack
[info] skip: bun does not subscribe to unary-grpc
[info] skip: bun does not subscribe to unary-grpc-tls
[info] skip: bun does not subscribe to stream-grpc
[info] skip: bun does not subscribe to stream-grpc-tls
[info] skip: bun does not subscribe to echo-ws
[info] skip: bun does not subscribe to echo-ws-pipeline
[info] skip: bun does not subscribe to echo-ws-limited
[info] rebuilding site/data/*.json
[updated] /home/diogo/actions-runner/_work/HttpArena/HttpArena/site/data/frameworks.json
[updated] /home/diogo/actions-runner/_work/HttpArena/HttpArena/site/data/results/bun.json - 24 new, 24 total
[updated] /home/diogo/actions-runner/_work/HttpArena/HttpArena/site/data/current.json
[info] done
httparena-postgres
httparena-redis
[info] restoring loopback MTU to 65536

@MDA2AV
MDA2AV merged commit 2273b81 into MDA2AV:main Aug 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants