← hyper.dev/letloop

HTTP server benchmark report

Counter application — single pinned core, 10s per concurrency level, wrk load generator

Fastest
C (h2o)
504,899 req/s (libh2o-evloop)
Runner-up
letloop
448,768 req/s (pico + io_uring)
Lowest p99
letloop
0.008ms
Implementations
16
languages tested

Peak throughput rankings

# Language Framework Peak req/s @ conns Avg (ms) p99 (ms)
1 C (h2o) libh2o-evloop 504,899 256 0.485 0.88
2 letloop pico + io_uring 448,768 64 0.137 0.159
3 Rust axum + tokio 410,948 8 0.019 0.021
4 Java (Vert.x) Vert.x 362,643 4 0.069 2.22
5 Bun (canary) Bun.serve() (canary, Rust) 316,374 64 0.215 0.299
6 Bun Bun.serve() 302,272 8 0.029 0.106
7 Deno Deno.serve() 264,358 8 0.029 0.036
8 Go net/http (stdlib) 224,278 8 0.037 0.090
9 Node.js http (stdlib) 192,824 4 0.027 0.052
10 Java (Loom) HttpServer + virtual threads 112,088 8 0.109 1.79
11 Gleam mist + gleam_otp 111,925 4 0.040 0.047
12 Common Lisp Hunchentoot 88,305 4 0.061 0.656
13 Racket web-server (stdlib) 68,474 16 0.234 0.279
14 FastAPI uvicorn 44,864 32 0.710 1.36
15 Ruby Falcon (async) 41,952 16 0.378 0.608
16 Flask gunicorn (1 worker) 12,397 1 0.083 0.107

Scaling data

C (h2o) libh2o-evloop

ConnsReq/sAvg (ms)p99 (ms)
1172,7520.0120.033
2330,6600.0070.010
4398,2280.0100.013
8411,0890.0150.024
16492,2970.1462.69
32486,4790.0670.126
64490,0700.1280.250
128493,2940.2380.457
256504,8990.4850.88

letloop pico + io_uring

ConnsReq/sAvg (ms)p99 (ms)
1163,9880.0060.008
2326,8540.0070.009
4401,6480.0090.012
8422,5230.0160.020
16446,9880.0370.047
32448,3920.0690.090
64448,7680.1370.159
128429,7200.2700.433
256396,0010.5880.843

Rust axum + tokio

ConnsReq/sAvg (ms)p99 (ms)
1142,5610.0090.009
2366,7980.0050.008
4399,3680.0100.011
8410,9480.0190.021
16386,4430.0440.045
32364,7130.0870.093
64356,5540.4120.232
128357,3340.3270.385
256341,0190.6850.96

Java (Vert.x) Vert.x

ConnsReq/sAvg (ms)p99 (ms)
1134,4610.0351.19
2328,2740.0632.22
4362,6430.0692.22
8360,1920.0952.47
16353,6070.1042.25
32351,9270.1522.43
64348,0550.2572.77
128339,6980.4223.20
256331,3540.7934.09

Bun (canary) Bun.serve() (canary, Rust)

ConnsReq/sAvg (ms)p99 (ms)
1127,9390.0110.033
2227,5550.0090.030
4276,4530.0160.049
8304,9940.0260.056
16311,1870.0520.102
32315,3070.1010.181
64316,3740.2150.299
128304,6810.3930.563
256279,7220.861.09

Bun Bun.serve()

ConnsReq/sAvg (ms)p99 (ms)
1120,3440.0130.063
2252,2720.0130.089
4291,2980.0150.075
8302,2720.0290.106
16295,7390.0600.195
32295,3560.1090.226
64293,6950.2250.370
128286,6120.4430.637
256280,9670.861.19

Deno Deno.serve()

ConnsReq/sAvg (ms)p99 (ms)
1100,4360.0130.015
2201,8720.0100.016
4241,4370.0160.019
8264,3580.0290.036
16258,1010.0620.092
32248,5650.1290.175
64244,8640.2650.306
128239,7770.5170.599
256233,1561.031.22

Go net/http (stdlib)

ConnsReq/sAvg (ms)p99 (ms)
1105,3400.0190.114
2213,8460.0100.030
4222,6730.0200.057
8224,2780.0370.090
16215,9930.0780.177
32213,7640.1500.317
64207,6690.3150.655
128201,0460.5851.25
256190,0861.252.17

Node.js http (stdlib)

ConnsReq/sAvg (ms)p99 (ms)
1106,8930.0290.794
2182,6580.0220.056
4192,8240.0270.052
8191,3930.0490.089
16190,0170.0900.162
32185,2130.1780.239
64182,0360.3610.427
128172,8410.7320.86
256167,9111.841.73

Java (Loom) HttpServer + virtual threads

ConnsReq/sAvg (ms)p99 (ms)
184,3870.0591.82
296,5750.0511.34
4106,7320.0661.29
8112,0880.1091.79
16110,5100.1842.03
32110,8080.3362.55
64110,6240.6383.10
128107,1131.143.63
25694,4783.366.98

Gleam mist + gleam_otp

ConnsReq/sAvg (ms)p99 (ms)
171,2250.0240.281
288,8210.0320.294
4111,9250.0400.047
8111,7610.0770.085
16111,0310.1470.177
32111,3640.2870.312
64109,7860.5720.610
128107,2341.091.33
256102,1442.352.89

Common Lisp Hunchentoot

ConnsReq/sAvg (ms)p99 (ms)
164,1510.0380.95
283,8440.0440.764
488,3050.0610.656
887,0960.1100.799
1687,3340.1930.596
3286,0440.3851.05
6483,8760.7992.51
12879,0191.616.91
25674,2246.1757.53

Racket web-server (stdlib)

ConnsReq/sAvg (ms)p99 (ms)
158,3050.0270.285
265,7600.0400.229
467,3930.0650.125
867,7700.1210.250
1668,4740.2340.279
3266,9800.4770.546
6466,4000.941.49
12866,0441.773.38
25662,5183.737.12

FastAPI uvicorn

ConnsReq/sAvg (ms)p99 (ms)
134,9190.0310.041
241,4310.0510.079
440,7560.1060.443
842,3520.1880.252
1643,8580.3640.608
3244,8640.7101.36
6444,1401.462.43
12844,5562.855.07
25643,1568.70140.71

Ruby Falcon (async)

ConnsReq/sAvg (ms)p99 (ms)
134,2330.0490.668
238,9070.0640.321
440,3450.1050.314
841,3340.1970.427
1641,9520.3780.608
3241,8320.7641.00
6439,6981.581.85
12836,9123.193.31
25636,5017.9635.21

Flask gunicorn (1 worker)

ConnsReq/sAvg (ms)p99 (ms)
112,3970.0830.107
211,9590.1720.408
412,0190.3350.468
811,9820.6691.08
1612,1131.321.50
3211,9412.682.98
6411,4075.526.12
12810,56511.0212.38
2569,71023.9926.92

Top 5 by concurrency level

Connections1st2nd3rd4th5th
1
1C (h2o)172,752 req/s
2letloop163,988 req/s
3Rust142,561 req/s
4Java (Vert.x)134,461 req/s
5Bun (canary)127,939 req/s
2
1Rust366,798 req/s
2C (h2o)330,660 req/s
3Java (Vert.x)328,274 req/s
4letloop326,854 req/s
5Bun252,272 req/s
4
1letloop401,648 req/s
2Rust399,368 req/s
3C (h2o)398,228 req/s
4Java (Vert.x)362,643 req/s
5Bun291,298 req/s
8
1letloop422,523 req/s
2C (h2o)411,089 req/s
3Rust410,948 req/s
4Java (Vert.x)360,192 req/s
5Bun (canary)304,994 req/s
16
1C (h2o)492,297 req/s
2letloop446,988 req/s
3Rust386,443 req/s
4Java (Vert.x)353,607 req/s
5Bun (canary)311,187 req/s
32
1C (h2o)486,479 req/s
2letloop448,392 req/s
3Rust364,713 req/s
4Java (Vert.x)351,927 req/s
5Bun (canary)315,307 req/s
64
1C (h2o)490,070 req/s
2letloop448,768 req/s
3Rust356,554 req/s
4Java (Vert.x)348,055 req/s
5Bun (canary)316,374 req/s
128
1C (h2o)493,294 req/s
2letloop429,720 req/s
3Rust357,334 req/s
4Java (Vert.x)339,698 req/s
5Bun (canary)304,681 req/s
256
1C (h2o)504,899 req/s
2letloop396,001 req/s
3Rust341,019 req/s
4Java (Vert.x)331,354 req/s
5Bun280,967 req/s