From c7c3eff8f0027d0d3ff5e9d42645c438aea1c21d Mon Sep 17 00:00:00 2001 From: Nigro Simone Date: Sun, 23 Aug 2026 07:56:58 +0200 Subject: [PATCH 1/2] bun: declare the endpoints in Bun.serve routes instead of branching on req.url --- frameworks/bun/meta.json | 2 +- frameworks/bun/server.ts | 70 +++++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/frameworks/bun/meta.json b/frameworks/bun/meta.json index 6ca84b9cb..514cf9cbb 100644 --- a/frameworks/bun/meta.json +++ b/frameworks/bun/meta.json @@ -4,7 +4,7 @@ "type": "flagship", "mode": "standard", "completeness": { - "routing": false, + "routing": true, "middleware": false, "request": true, "response": true diff --git a/frameworks/bun/server.ts b/frameworks/bun/server.ts index 078804324..26bff1a52 100644 --- a/frameworks/bun/server.ts +++ b/frameworks/bun/server.ts @@ -79,8 +79,8 @@ async function baseline11Post(req: Request, sum: number): Promise { return new Response(String(Number.isNaN(n) ? sum : sum + n), { headers: TEXT }); } -function json(path: string, query: string, req: Request): Response { - let count = parseInt(path.slice(6), 10); +function json(count_: string, query: string, req: Request): Response { + let count = parseInt(count_, 10); if (!(count > 0)) count = 0; if (count > dataset.length) count = dataset.length; const m = multiplier(query); @@ -151,8 +151,7 @@ const ENCODINGS: ReadonlyArray = [ ["gzip", ".gz"], ]; -async function serveStatic(path: string, req: Request): Promise { - const name = path.slice(8); +async function serveStatic(name: string, req: Request): Promise { // No traversal outside the mount, and no directory reads. if (name.length === 0 || name.includes("/") || name.includes("..")) { return new Response("Not Found", { status: 404, headers: TEXT }); @@ -319,46 +318,48 @@ async function fortunes(): Promise { } } -function handle(req: Request): Response | Promise { - // req.url is absolute, so the path starts at the first slash after the host. - const url = req.url; - const start = url.indexOf("/", 8); - const q = url.indexOf("?", start); - const path = q < 0 ? url.slice(start) : url.slice(start, q); - const query = q < 0 ? "" : url.slice(q + 1); +// The query string, which is the one part of the request the router does not hand over. +const qs = (req: Request): string => { + const q = req.url.indexOf("?"); + return q < 0 ? "" : req.url.slice(q + 1); +}; - if (path === "/pipeline") return new Response("ok", { headers: TEXT }); +// Bun.serve matches method and path itself and fills in req.params, so this entry declares its +// endpoints rather than branching on req.url. `fetch` below is only what is left when nothing +// matched. +const routes = { + "/pipeline": () => new Response("ok", { headers: TEXT }), - if (path === "/baseline11") { - const sum = sumQuery(query); - if (req.method === "POST") return baseline11Post(req, sum); - return new Response(String(sum), { headers: TEXT }); - } + "/baseline11": { + GET: (req: Request) => new Response(String(sumQuery(qs(req))), { headers: TEXT }), + POST: (req: Request) => baseline11Post(req, sumQuery(qs(req))), + }, - if (path.startsWith("/json/")) return json(path, query, req); + "/baseline2": (req: Request) => new Response(String(sumQuery(qs(req))), { headers: TEXT }), - if (path === "/upload" && req.method === "POST") return upload(req); + "/json/:count": (req: any) => json(req.params.count, qs(req), req), - if (path === "/baseline2") return new Response(String(sumQuery(query)), { headers: TEXT }); + "/upload": { POST: (req: Request) => upload(req) }, - if (path.startsWith("/static/")) return serveStatic(path, req); + // one segment, so a path with a slash in it never reaches the handler + "/static/:name": (req: any) => serveStatic(req.params.name, req), - if (path === "/async-db") return asyncDb(query); + "/async-db": (req: Request) => asyncDb(qs(req)), - if (path === "/fortunes") return fortunes(); + "/fortunes": () => fortunes(), - if (path.startsWith("/crud/items")) { - if (path === "/crud/items") { - if (req.method === "POST") return crudCreate(req); - return crudList(query); - } - if (path.charCodeAt(11) === 47 /* "/" */) { - const id = parseInt(path.slice(12), 10); - if (req.method === "PUT") return crudUpdate(req, id); - return crudRead(id); - } - } + "/crud/items": { + GET: (req: Request) => crudList(qs(req)), + POST: (req: Request) => crudCreate(req), + }, + + "/crud/items/:id": { + GET: (req: any) => crudRead(parseInt(req.params.id, 10)), + PUT: (req: any) => crudUpdate(req, parseInt(req.params.id, 10)), + }, +}; +function handle(): Response { return new Response("Not Found", { status: 404, headers: TEXT }); } @@ -370,6 +371,7 @@ const listener = { development: false, // A 20 MB upload on a saturated server takes longer than the 10s default. idleTimeout: 120, + routes, fetch: handle, }; From 57e2b20e978aba1df9bfbdca21551bc3d92e59fc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 23 Aug 2026 23:42:38 +0000 Subject: [PATCH 2/2] Benchmark results: bun [skip ci] --- site/data/frameworks.json | 2 +- site/data/results/bun.json | 374 ++++++++++++++++++------------------- 2 files changed, 188 insertions(+), 188 deletions(-) diff --git a/site/data/frameworks.json b/site/data/frameworks.json index 04d3382a8..c137b6b3a 100644 --- a/site/data/frameworks.json +++ b/site/data/frameworks.json @@ -242,7 +242,7 @@ "engine": "bun", "mode": "standard", "completeness": { - "routing": false, + "routing": true, "middleware": false, "request": true, "response": true diff --git a/site/data/results/bun.json b/site/data/results/bun.json index bc6af6bcc..ba94f15d0 100644 --- a/site/data/results/bun.json +++ b/site/data/results/bun.json @@ -4,71 +4,71 @@ "api-16-1024": { "framework": "bun", "language": "TS", - "rps": 154060, - "avg_latency": "4.86ms", - "p99_latency": "30.20ms", - "cpu": "1504.4%", - "memory": "594MiB", + "rps": 152696, + "avg_latency": "4.71ms", + "p99_latency": "31.00ms", + "cpu": "1494.5%", + "memory": "595MiB", "connections": 1024, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "776.31MB/s", - "input_bw": "8.67MB/s", - "reconnects": 461975, - "status_2xx": 2310909, + "bandwidth": "769.45MB/s", + "input_bw": "8.59MB/s", + "reconnects": 457865, + "status_2xx": 2290441, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0, - "tpl_baseline": 866657, - "tpl_json": 866532, + "tpl_baseline": 858999, + "tpl_json": 858875, "tpl_db": 0, "tpl_upload": 0, "tpl_static": 0, - "tpl_async_db": 577720 + "tpl_async_db": 572566 }, "api-4-256": { "framework": "bun", "language": "TS", - "rps": 43980, - "avg_latency": "4.34ms", - "p99_latency": "23.50ms", - "cpu": "392.1%", - "memory": "158MiB", + "rps": 43637, + "avg_latency": "4.22ms", + "p99_latency": "24.40ms", + "cpu": "393.3%", + "memory": "156MiB", "connections": 256, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "221.63MB/s", - "input_bw": "2.47MB/s", - "reconnects": 131920, - "status_2xx": 659700, + "bandwidth": "219.93MB/s", + "input_bw": "2.46MB/s", + "reconnects": 130929, + "status_2xx": 654564, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0, - "tpl_baseline": 247360, - "tpl_json": 247327, + "tpl_baseline": 245393, + "tpl_json": 245346, "tpl_db": 0, "tpl_upload": 0, "tpl_static": 0, - "tpl_async_db": 165013 + "tpl_async_db": 163824 }, "async-db-1024": { "framework": "bun", "language": "TS", - "rps": 278613, - "avg_latency": "3.09ms", - "p99_latency": "16.80ms", - "cpu": "5153.3%", - "memory": "2.1GiB", + "rps": 277270, + "avg_latency": "3.11ms", + "p99_latency": "16.70ms", + "cpu": "5156.2%", + "memory": "2.2GiB", "connections": 1024, "threads": 64, "duration": "5s", "pipeline": 1, "bandwidth": "1.04GB/s", - "input_bw": "18.60MB/s", - "reconnects": 111233, - "status_2xx": 2786133, + "input_bw": "18.51MB/s", + "reconnects": 110639, + "status_2xx": 2772709, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -76,19 +76,19 @@ "baseline-4096": { "framework": "bun", "language": "TS", - "rps": 1907836, - "avg_latency": "2.15ms", - "p99_latency": "3.78ms", - "cpu": "6748.2%", + "rps": 1933399, + "avg_latency": "2.12ms", + "p99_latency": "3.82ms", + "cpu": "6739.6%", "memory": "1.2GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "211.00MB/s", - "input_bw": "147.38MB/s", + "bandwidth": "213.83MB/s", + "input_bw": "149.35MB/s", "reconnects": 0, - "status_2xx": 9539181, + "status_2xx": 9666996, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -96,19 +96,19 @@ "baseline-512": { "framework": "bun", "language": "TS", - "rps": 1776235, - "avg_latency": "287us", - "p99_latency": "823us", - "cpu": "6743.7%", + "rps": 1806113, + "avg_latency": "282us", + "p99_latency": "817us", + "cpu": "6742.0%", "memory": "1.3GiB", "connections": 512, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "196.45MB/s", - "input_bw": "137.21MB/s", + "bandwidth": "199.75MB/s", + "input_bw": "139.52MB/s", "reconnects": 0, - "status_2xx": 8881178, + "status_2xx": 9030565, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -116,19 +116,19 @@ "crud-4096": { "framework": "bun", "language": "TS", - "rps": 310372, - "avg_latency": "13.12ms", - "p99_latency": "24.80ms", - "cpu": "2944.6%", + "rps": 312418, + "avg_latency": "13.00ms", + "p99_latency": "24.00ms", + "cpu": "2841.3%", "memory": "1.5GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "104.18MB/s", - "input_bw": "26.64MB/s", - "reconnects": 22416, - "status_2xx": 4655589, + "bandwidth": "104.65MB/s", + "input_bw": "26.82MB/s", + "reconnects": 22662, + "status_2xx": 4686279, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -136,18 +136,18 @@ "fortunes-1024": { "framework": "bun", "language": "TS", - "rps": 83423, - "avg_latency": "9.17ms", - "p99_latency": "22.80ms", - "cpu": "6479.9%", + "rps": 83251, + "avg_latency": "8.81ms", + "p99_latency": "22.00ms", + "cpu": "6392.8%", "memory": "2.0GiB", "connections": 1024, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "1.93GB/s", + "bandwidth": "1.92GB/s", "reconnects": 0, - "status_2xx": 417119, + "status_2xx": 416257, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -155,19 +155,19 @@ "json-4096": { "framework": "bun", "language": "TS", - "rps": 1118584, - "avg_latency": "3.30ms", - "p99_latency": "10.30ms", - "cpu": "6387.1%", - "memory": "1012MiB", + "rps": 1119942, + "avg_latency": "3.29ms", + "p99_latency": "10.40ms", + "cpu": "6511.8%", + "memory": "1.1GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "3.79GB/s", - "input_bw": "53.34MB/s", - "reconnects": 223375, - "status_2xx": 5592920, + "bandwidth": "3.80GB/s", + "input_bw": "53.40MB/s", + "reconnects": 222856, + "status_2xx": 5599713, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -175,19 +175,19 @@ "json-comp-16384": { "framework": "bun", "language": "TS", - "rps": 468757, - "avg_latency": "34.62ms", - "p99_latency": "59.50ms", - "cpu": "6521.8%", + "rps": 466635, + "avg_latency": "34.85ms", + "p99_latency": "60.50ms", + "cpu": "6527.8%", "memory": "1.2GiB", "connections": 16384, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "626.66MB/s", - "input_bw": "34.87MB/s", - "reconnects": 85393, - "status_2xx": 2343788, + "bandwidth": "623.88MB/s", + "input_bw": "34.71MB/s", + "reconnects": 84983, + "status_2xx": 2333177, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -195,19 +195,19 @@ "json-comp-4096": { "framework": "bun", "language": "TS", - "rps": 464736, - "avg_latency": "8.80ms", - "p99_latency": "21.20ms", - "cpu": "6395.9%", + "rps": 463429, + "avg_latency": "8.82ms", + "p99_latency": "21.10ms", + "cpu": "6467.9%", "memory": "1.1GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "621.37MB/s", - "input_bw": "34.57MB/s", - "reconnects": 91594, - "status_2xx": 2323681, + "bandwidth": "619.61MB/s", + "input_bw": "34.47MB/s", + "reconnects": 91064, + "status_2xx": 2317146, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -215,19 +215,19 @@ "json-comp-512": { "framework": "bun", "language": "TS", - "rps": 431226, + "rps": 430945, "avg_latency": "1.18ms", - "p99_latency": "5.13ms", - "cpu": "6067.1%", + "p99_latency": "5.05ms", + "cpu": "6064.4%", "memory": "1.1GiB", "connections": 512, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "576.55MB/s", - "input_bw": "32.08MB/s", - "reconnects": 86265, - "status_2xx": 2156133, + "bandwidth": "576.12MB/s", + "input_bw": "32.06MB/s", + "reconnects": 86212, + "status_2xx": 2154726, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -235,18 +235,18 @@ "json-tls-4096": { "framework": "bun", "language": "TS", - "rps": 1088357, - "avg_latency": "3.77ms", - "p99_latency": "62.79ms", - "cpu": "6470.9%", + "rps": 1076199, + "avg_latency": "3.84ms", + "p99_latency": "85.07ms", + "cpu": "6320.6%", "memory": "1.0GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "3.69GB", + "bandwidth": "3.65GB", "reconnects": 0, - "status_2xx": 5550811, + "status_2xx": 5482533, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -254,19 +254,19 @@ "limited-conn-4096": { "framework": "bun", "language": "TS", - "rps": 1638140, - "avg_latency": "2.49ms", - "p99_latency": "8.92ms", - "cpu": "6387.4%", - "memory": "1.1GiB", + "rps": 1649543, + "avg_latency": "2.47ms", + "p99_latency": "8.89ms", + "cpu": "6410.1%", + "memory": "1.2GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "181.17MB/s", - "input_bw": "126.54MB/s", - "reconnects": 818288, - "status_2xx": 8190701, + "bandwidth": "182.43MB/s", + "input_bw": "127.42MB/s", + "reconnects": 825121, + "status_2xx": 8247715, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -274,19 +274,19 @@ "limited-conn-512": { "framework": "bun", "language": "TS", - "rps": 1383333, - "avg_latency": "360us", - "p99_latency": "1.65ms", - "cpu": "6256.9%", + "rps": 1394461, + "avg_latency": "357us", + "p99_latency": "1.76ms", + "cpu": "6215.0%", "memory": "1.1GiB", "connections": 512, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "153.00MB/s", - "input_bw": "106.86MB/s", - "reconnects": 691677, - "status_2xx": 6916668, + "bandwidth": "154.22MB/s", + "input_bw": "107.72MB/s", + "reconnects": 697253, + "status_2xx": 6972305, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -294,18 +294,18 @@ "pipelined-4096": { "framework": "bun", "language": "TS", - "rps": 340169, - "avg_latency": "148.67ms", - "p99_latency": "224.60ms", - "cpu": "6730.4%", - "memory": "693MiB", + "rps": 346547, + "avg_latency": "145.50ms", + "p99_latency": "227.90ms", + "cpu": "6593.0%", + "memory": "863MiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 16, - "bandwidth": "38.24MB/s", - "reconnects": 53, - "status_2xx": 1700849, + "bandwidth": "38.96MB/s", + "reconnects": 62, + "status_2xx": 1732737, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -313,18 +313,18 @@ "pipelined-512": { "framework": "bun", "language": "TS", - "rps": 89360, - "avg_latency": "14.16ms", - "p99_latency": "35.30ms", - "cpu": "2116.0%", - "memory": "826MiB", + "rps": 90898, + "avg_latency": "14.48ms", + "p99_latency": "46.30ms", + "cpu": "1867.8%", + "memory": "550MiB", "connections": 512, "threads": 64, "duration": "5s", "pipeline": 16, - "bandwidth": "10.06MB/s", - "reconnects": 18, - "status_2xx": 446803, + "bandwidth": "10.23MB/s", + "reconnects": 22, + "status_2xx": 454491, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -332,18 +332,18 @@ "static-1024": { "framework": "bun", "language": "TS", - "rps": 571082, - "avg_latency": "1.97ms", - "p99_latency": "69.27ms", - "cpu": "6584.9%", - "memory": "1.2GiB", + "rps": 573475, + "avg_latency": "1.92ms", + "p99_latency": "35.20ms", + "cpu": "6592.1%", + "memory": "1.1GiB", "connections": 1024, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "8.72GB", + "bandwidth": "8.75GB", "reconnects": 0, - "status_2xx": 2912193, + "status_2xx": 2924437, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -351,18 +351,18 @@ "static-4096": { "framework": "bun", "language": "TS", - "rps": 566836, - "avg_latency": "7.38ms", - "p99_latency": "60.83ms", - "cpu": "6557.8%", - "memory": "1.2GiB", + "rps": 570062, + "avg_latency": "7.33ms", + "p99_latency": "60.17ms", + "cpu": "6581.8%", + "memory": "1.1GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "8.65GB", + "bandwidth": "8.70GB", "reconnects": 0, - "status_2xx": 2890752, + "status_2xx": 2907337, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -370,18 +370,18 @@ "static-6800": { "framework": "bun", "language": "TS", - "rps": 556167, - "avg_latency": "12.32ms", - "p99_latency": "116.48ms", - "cpu": "6552.4%", + "rps": 560918, + "avg_latency": "12.22ms", + "p99_latency": "86.78ms", + "cpu": "6565.4%", "memory": "1.2GiB", "connections": 6800, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "8.49GB", + "bandwidth": "8.56GB", "reconnects": 0, - "status_2xx": 2837019, + "status_2xx": 2861261, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -389,18 +389,18 @@ "static-tls-1024": { "framework": "bun", "language": "TS", - "rps": 491299, - "avg_latency": "2.24ms", - "p99_latency": "53.40ms", - "cpu": "6572.7%", - "memory": "1.2GiB", + "rps": 484123, + "avg_latency": "2.28ms", + "p99_latency": "52.37ms", + "cpu": "6559.5%", + "memory": "1.1GiB", "connections": 1024, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "7.50GB", + "bandwidth": "7.39GB", "reconnects": 0, - "status_2xx": 2505667, + "status_2xx": 2469115, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -408,18 +408,18 @@ "static-tls-4096": { "framework": "bun", "language": "TS", - "rps": 474144, - "avg_latency": "8.76ms", - "p99_latency": "89.40ms", - "cpu": "6545.2%", - "memory": "1.2GiB", + "rps": 472364, + "avg_latency": "8.82ms", + "p99_latency": "158.86ms", + "cpu": "6478.5%", + "memory": "1.1GiB", "connections": 4096, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "7.24GB", + "bandwidth": "7.21GB", "reconnects": 0, - "status_2xx": 2417131, + "status_2xx": 2408605, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -427,18 +427,18 @@ "static-tls-6800": { "framework": "bun", "language": "TS", - "rps": 463754, - "avg_latency": "14.79ms", - "p99_latency": "169.74ms", - "cpu": "6529.3%", + "rps": 461360, + "avg_latency": "14.83ms", + "p99_latency": "157.32ms", + "cpu": "6388.3%", "memory": "1.2GiB", "connections": 6800, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "7.08GB", + "bandwidth": "7.04GB", "reconnects": 0, - "status_2xx": 2365173, + "status_2xx": 2352313, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -446,19 +446,19 @@ "upload-256": { "framework": "bun", "language": "TS", - "rps": 1996, - "avg_latency": "125.35ms", - "p99_latency": "876.30ms", - "cpu": "5723.9%", + "rps": 1988, + "avg_latency": "124.38ms", + "p99_latency": "907.80ms", + "cpu": "5862.1%", "memory": "2.6GiB", "connections": 256, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "236.36KB/s", - "input_bw": "15.83GB/s", - "reconnects": 1973, - "status_2xx": 10004, + "bandwidth": "235.23KB/s", + "input_bw": "15.77GB/s", + "reconnects": 1956, + "status_2xx": 9941, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 @@ -466,19 +466,19 @@ "upload-32": { "framework": "bun", "language": "TS", - "rps": 1909, - "avg_latency": "16.73ms", - "p99_latency": "98.00ms", - "cpu": "3023.8%", + "rps": 1913, + "avg_latency": "16.69ms", + "p99_latency": "101.20ms", + "cpu": "3069.7%", "memory": "2.4GiB", "connections": 32, "threads": 64, "duration": "5s", "pipeline": 1, - "bandwidth": "226.02KB/s", - "input_bw": "15.14GB/s", - "reconnects": 1910, - "status_2xx": 9548, + "bandwidth": "226.49KB/s", + "input_bw": "15.17GB/s", + "reconnects": 1915, + "status_2xx": 9569, "status_3xx": 0, "status_4xx": 0, "status_5xx": 0