Benchmarks

@dunx/http against raw Bun.serve, Elysia, Hono, Fastify, Express and bare node:http. The number worth having is the gap to raw Bun.serve: dunx is a layer on that exact API, so the gap is dunx's own overhead. Rows are ordered by measured throughput, losses included, and request logging gets its own row rather than being folded into the framework's number.

AMD Ryzen 9 5950X 16-Core Processor, 32 logical cores, 62.7 GiB RAM · linux 7.0.0-31-generic x64 · bun 1.4.2 · node v24.21.0

64 connections · 3s warmup · 5 x 5s measured (median) · 7 startup samples · oha 1.15.0

Wed, 09 Sep 2026 05:01:39 GMT
every row ranked

dunx vs raw Bun.serve

92.1-99.7%

of the ceiling, across 5 scenarios. The rest is framework overhead.

Against the fastest rival

0W 3T 2L

Won 0, tied 3, lost 2 of 5. A gap inside ±3 points is a tie on this setup, not a result.

Cold start

1.93x

46.2 ms against Bun.serve (raw)'s 24.0 ms - rank 6 of 20. dunx's clearest loss on this page.

Scenario by scenario

ScenariodunxFastest rivalRankVerdict
Plain text99.6%Elysia 99.0%2 / 20
tied
JSON95.6%Axum (Rust) 97.8%3 / 20
tied
Path parameter94.4%Elysia 99.6%4 / 20
behind
Body validation92.1%Axum (Rust) 93.7%3 / 20
tied
Cache and database99.7%Axum (Rust) 127.1%4 / 20
behind

Bun

Node

Go

Rust

JVM

.NET

Python

@dunx/http

Plain text

GET /plaintext

GET returning a fixed text/plain body. Measures raw request/response dispatch.

SubjectThroughput vs raw Bun.servereq/s± stddevp50 msp99 mspeak MiBcpu ms/kreq
Bun.serve (raw)

100.0%

134,4785140.4530.91447.17.70
@dunx/http

99.6%

133,9931,2030.4580.92161.57.76
Elysia

99.0%

133,1511,6980.4590.93054.87.88
Axum (Rust)

94.4%

126,9691,2020.4990.5534.87.89
Hono (Bun)

92.1%

123,8152,4550.4950.99952.58.44
ASP.NET Core minimal APIs

82.3%

110,6492,3560.5580.80398.811.32
ASP.NET Core MVC

66.0%

88,7021,3110.6970.982104.413.57
@dunx/http (+ request logging)

59.9%

80,6185940.7611.50769.613.19
Gin (Go)

56.9%

76,4804180.8311.91022.513.09
net/http (Go)

55.8%

74,9764230.8511.86717.913.36
@dunx/http (+ request logging, @arkv/logger)

44.6%

59,9671,2301.0001.99176.317.57
node:http (raw)

39.7%

53,3258141.1622.29586.118.81
Spring Boot (JVM)

38.7%

52,073771.2051.721352.328.79
Fastify (Node)

34.5%

46,4431,4561.3551.81492.922.12
Hono (Node)

30.6%

41,2011,2511.5381.94389.424.55
NestJS (Fastify)

27.6%

37,1781,8641.6232.173109.427.85
Express (Node)

20.5%

27,5617682.2752.73592.736.77
NestJS (Express)

14.6%

19,6402563.1453.573109.651.99
FastAPI (Python)

5.4%

7,321718.7259.01244.1136.34
Django (Python)

3.4%

4,5381814.02215.30873.6220.01

JSON

GET /json

GET returning a small object serialised to JSON. Adds serialisation cost.

SubjectThroughput vs raw Bun.servereq/s± stddevp50 msp99 mspeak MiBcpu ms/kreq
Bun.serve (raw)

100.0%

129,6411,3540.4700.94446.37.96
Axum (Rust)

97.8%

126,8056440.5000.5744.87.89
@dunx/http

95.6%

123,9991,6180.4930.99060.38.33
Elysia

94.3%

122,2201,0940.5011.01055.58.59
Hono (Bun)

86.9%

112,7171,6240.5441.09554.99.29
ASP.NET Core minimal APIs

81.6%

105,8331,3560.5900.795102.211.90
ASP.NET Core MVC

65.1%

84,3931,7440.7341.016106.714.14
@dunx/http (+ request logging)

59.4%

77,0159910.7911.56168.013.84
Gin (Go)

57.8%

74,8748660.8501.95522.413.37
net/http (Go)

57.4%

74,3633120.8591.88717.913.46
@dunx/http (+ request logging, @arkv/logger)

44.8%

58,0518281.0462.08270.318.33
Spring Boot (JVM)

39.5%

51,2291861.2331.464600.928.90
node:http (raw)

37.7%

48,8821,8111.2852.50286.220.53
Fastify (Node)

34.0%

44,0401,5051.3921.84392.123.37
NestJS (Fastify)

30.3%

39,2541,1521.5772.458109.726.32
Hono (Node)

28.5%

36,9168631.6862.07592.027.99
Express (Node)

20.3%

26,2752402.3852.64492.738.41
NestJS (Express)

13.9%

17,9744913.5394.022107.457.02
FastAPI (Python)

5.6%

7,258228.8029.06144.0137.71
Django (Python)

3.4%

4,4254514.38916.09873.9225.74

Path parameter

GET /params/42

GET with one path parameter echoed back as JSON. Adds route-matching cost.

SubjectThroughput vs raw Bun.servereq/s± stddevp50 msp99 mspeak MiBcpu ms/kreq
Bun.serve (raw)

100.0%

128,1721,1990.4780.96147.98.06
Elysia

99.6%

127,7011,3580.4820.97456.48.20
Axum (Rust)

95.7%

122,7188800.5140.6334.88.14
@dunx/http

94.4%

120,9422,1300.4981.00761.58.58
Hono (Bun)

84.8%

108,6691,4340.5641.13354.19.66
ASP.NET Core minimal APIs

82.0%

105,0772,3090.5960.81999.911.83
@dunx/http (+ request logging)

59.0%

75,5771,1440.8071.60069.514.12
Gin (Go)

58.3%

74,7084150.8501.96922.513.40
net/http (Go)

57.3%

73,4488380.8701.89717.613.62
ASP.NET Core MVC

53.1%

68,1231,7400.9031.240105.917.24
@dunx/http (+ request logging, @arkv/logger)

44.4%

56,8991,3011.0742.14464.718.75
node:http (raw)

36.9%

47,3481,5601.3552.47686.021.24
Spring Boot (JVM)

34.7%

44,4591,0141.4141.769628.833.03
Fastify (Node)

34.0%

43,5686991.4221.93092.223.45
NestJS (Fastify)

26.6%

34,1104901.8062.242109.030.22
Hono (Node)

26.6%

34,0431,0961.8092.32493.930.34
Express (Node)

19.9%

25,4434222.4562.92791.239.95
NestJS (Express)

13.6%

17,4464463.6374.086108.357.98
FastAPI (Python)

5.2%

6,677559.5499.99643.3149.78
Django (Python)

3.4%

4,3638414.50815.83872.5228.91

Body validation

POST /validate

POST with a JSON body parsed and validated against the same zod schema in every subject, echoed back.

SubjectThroughput vs raw Bun.servereq/s± stddevp50 msp99 mspeak MiBcpu ms/kreq
Bun.serve (raw)

100.0%

90,0158920.6871.36951.011.53
Axum (Rust)

93.7%

84,3203,3970.7580.8125.511.86
@dunx/http

92.1%

82,9031,5510.7271.46068.212.58
Elysia

89.3%

80,3721,0740.7571.52057.213.21
ASP.NET Core minimal APIs

86.2%

77,5602,3090.7981.097101.915.26
Hono (Bun)

73.6%

66,2881,5850.9121.81955.715.95
@dunx/http (+ request logging)

64.0%

57,6028891.0601.97973.018.49
ASP.NET Core MVC

59.0%

53,1279761.1691.614107.321.18
Gin (Go)

56.1%

50,459701.2692.82622.519.88
net/http (Go)

55.4%

49,8843461.2882.77317.220.07
@dunx/http (+ request logging, @arkv/logger)

48.4%

43,6071,2871.3902.71871.024.52
Spring Boot (JVM)

37.7%

33,9445611.8292.233635.041.42
node:http (raw)

35.6%

32,0131,3641.8883.73490.431.84
Fastify (Node)

25.1%

22,5844032.6209.675258.652.47
Hono (Node)

22.5%

20,2259183.0965.751105.749.70
NestJS (Fastify)

22.0%

19,7884743.0647.645278.158.25
Express (Node)

19.2%

17,3124413.6424.40197.458.17
NestJS (Express)

14.6%

13,1222804.8155.479115.077.17
FastAPI (Python)

4.9%

4,4032314.50214.88744.2227.13
Django (Python)

4.7%

4,1996115.13216.78073.8237.85

Cache and database

GET /io

GET reading one key from Redis and then one indexed row from Postgres with a bound parameter, merged into one JSON object.

SubjectThroughput vs raw Bun.servereq/s± stddevp50 msp99 mspeak MiBcpu ms/kreq
Axum (Rust)

127.1%

35,2282461.8102.0946.128.36
Elysia

100.1%

27,7412482.2963.51666.338.41
Bun.serve (raw)

100.0%

27,7211912.3083.52460.538.26
@dunx/http

99.7%

27,6463472.3053.59771.938.74
Hono (Bun)

95.6%

26,4945182.4063.78264.140.69
@dunx/http (+ request logging)

89.2%

24,7343632.5534.18878.244.35
@dunx/http (+ request logging, @arkv/logger)

81.2%

22,5171112.8384.49480.647.83
ASP.NET Core minimal APIs

77.0%

21,3552612.9633.940122.768.45
Gin (Go)

75.6%

20,9452542.9644.35528.147.71
net/http (Go)

74.9%

20,7642392.9954.31823.148.12
ASP.NET Core MVC

67.2%

18,6231373.3914.658129.077.24
Fastify (Node)

52.4%

14,5204154.3235.881121.870.54
node:http (raw)

51.5%

14,2676124.3176.040113.272.12
NestJS (Fastify)

47.4%

13,1403834.7366.671158.377.79
Hono (Node)

46.5%

12,8994244.8046.422145.579.13
Express (Node)

39.5%

10,9594325.6797.670130.093.11
NestJS (Express)

35.8%

9,9112396.2378.331159.9103.76
Spring Boot (JVM)

17.8%

4,9444412.89814.341367.8109.19
FastAPI (Python)

7.7%

2,1301429.08545.82864.6469.69
Django (Python)

5.7%

1,5802140.46143.469104.9441.49

Cold start

Process spawn to first served request, median of 7 samples. Polled at about 1 ms, so treat anything under 5 ms as a tie.

SubjectCold start - shorter is bettermedian msmin msmax msvs Bun.serve
Axum (Rust)
1.71.61.90.07x
net/http (Go)
4.03.84.30.17x
Gin (Go)
5.04.15.30.21x
Bun.serve (raw)
24.022.525.11.00x
Hono (Bun)
27.426.328.81.14x
@dunx/http
46.243.247.11.93x
@dunx/http (+ request logging)
46.644.648.11.94x
Elysia
51.949.057.02.17x
@dunx/http (+ request logging, @arkv/logger)
61.455.863.42.56x
node:http (raw)
80.776.383.33.37x
Hono (Node)
95.590.297.93.99x
Express (Node)
110.1108.4115.04.60x
Django (Python)
131.4128.0132.85.48x
Fastify (Node)
135.4131.2138.35.65x
NestJS (Express)
243.7231.0258.210.17x
FastAPI (Python)
244.0239.9245.610.19x
NestJS (Fastify)
251.8246.1261.410.51x
ASP.NET Core MVC
297.8292.1305.912.43x
ASP.NET Core minimal APIs
299.6281.2312.912.51x
Spring Boot (JVM)
1322.51274.71358.055.21x

Memory

Resident set of the whole process tree, read from /proc at 20 Hz inside each measured window. Boot is taken after the first served request and before any load; peak is the highest sample under it. Runs are seconds long, so neither says anything about heap growth at hour six.

SubjectPeak resident set - smaller is betterboot MiBpeak MiBprocesses
Axum (Rust)
3.56.11
net/http (Go)
12.423.31
Gin (Go)
17.528.41
Bun.serve (raw)
34.662.81
FastAPI (Python)
43.064.61
Hono (Bun)
36.666.51
Elysia
47.268.91
@dunx/http
51.372.61
@dunx/http (+ request logging)
52.179.21
@dunx/http (+ request logging, @arkv/logger)
54.885.81
Django (Python)
73.5104.92
ASP.NET Core minimal APIs
76.4123.41
ASP.NET Core MVC
80.6129.81
node:http (raw)
72.6137.81
Express (Node)
73.7139.61
Hono (Node)
77.2148.41
NestJS (Express)
99.0181.61
Fastify (Node)
79.1269.11
NestJS (Fastify)
99.3278.41
Spring Boot (JVM)
259.2635.01

Stability

Throughput answers how fast one request is. This answers whether the process survives the night. bun run soak drives 28 weighted operations against the full example - HTTP, websocket churn, SQLite, Redis, S3, the queue, the outbound client, guards, auth, validation failures and rate limiting - and fits the settled heap across rounds rather than the in-flight series, which measures the allocator instead of a leak.

3,668,137

calls in 365s

10,051/s

sustained

0

failures

25.1 to 25.0 MiB

settled heap, 12 rounds

The same harness runs in CI at 40 seconds and concurrency 12, which is too short for a leak verdict and long enough to catch an unexpected status, a stalled loop, a subscriber that outlived its socket, and a shutdown that hangs.