Server Benchmarks

August 12, 2026 ยท View on GitHub

CI Go Report Card Go Reference License: MIT

A benchmark suite that stress-tests real web framework applications and writes the results as Markdown tables, SVG charts, CSV files and a machine-readable results.json.

The measuring is done by bombardier, a third-party HTTP load generator, not by this suite. Every framework runs as a self-contained program under _code/, written the way its own documentation recommends. Anyone can read the app code, run the same command and compare numbers.

Frameworks

FrameworkLanguageVersion source
IrisGo_code/*/iris/go.mod
GinGo_code/*/gin/go.mod
EchoGo_code/*/echo/go.mod
ChiGo_code/*/chi/go.mod
FiberGo_code/*/fiber/go.mod
net/http (standard library baseline)Go_code/*/nethttp/go.mod
ExpressJavascript_code/*/express/package.json
KoaJavascript_code/*/koa/package.json
FastifyJavascript_code/*/fastify/package.json
ASP.NET Core minimal APIsC#_code/*/aspnetcore/*.csproj

Versions are pinned in each app's manifest and kept current by Dependabot. Node apps run one worker per CPU through the builtin node:cluster module, since a single Node process is single-threaded; Go and .NET runtimes schedule across cores on their own.

Tests

TestRequestWhat it exercises
StaticGET /routing, plain text response
ParameterizedGET /hello/{name}dynamic path parameters
RESTPOST /{id} with a ~1MB JSON arrayrouting constraints, JSON decode and encode (2MB body limit)

Each test fires 100000 requests over 125 concurrent connections. All of it is configuration, not code: see the schema comment at the top of tests.yml.

Install

The tool itself only needs the Go Programming Language:

go install github.com/kataras/server-benchmarks@latest
go install github.com/codesenberg/bombardier@latest

Node.js 24+ and the .NET SDK 10 are needed only for the Javascript and C# environments. Without them, select the Go environments with -t, or let those environments fail and read the partial report.

Usage

server-benchmarks                # run everything in ./tests.yml, write reports to ./
server-benchmarks list           # print the tests and environments without running
server-benchmarks version        # print version information
server-benchmarks help           # global help

The run subcommand (implied when omitted) accepts:

FlagDefaultMeaning
-i./tests.ymlspec file to read
-o./output directory for the reports
-t(all)run only a test or a single test.env; repeatable
-wait-run3sidle time between two benchmarks
-readmeoffalso generate a publishable README.md
-bombardierfrom PATHpath of the bombardier executable
-voffdebug logging, including the servers' own output
# only the REST test, plus one specific pairing:
server-benchmarks run -t rest -t static.iris

# a development spec into a separate directory:
server-benchmarks run -i ./tests.dev.yml -o ./dev -wait-run 5s

A finished run leaves behind RESULTS.md, one <test>.csv and <test>_latency.csv per test, one <test>.svg and <test>_latency.svg chart per test, and results.json. The charts are embedded in RESULTS.md and adapt to light and dark GitHub themes.

export re-renders every artifact from a saved results.json, so you can regenerate reports after a template change without benchmarking again:

server-benchmarks export -i ./results.json -o ./

Test a private or unreleased framework

An environment does not need a public repository. Point it at any local directory that contains a runnable server implementing the test's contract:

Envs:
  - Name: Iris (next)
    Dir: C:/github/iris-private/_benchmarks/static

For an unreleased version of a framework that already has apps here, copy the app instead (e.g. _code/static/iris to _code/static/iris-next) and add a replace directive to its go.mod:

replace github.com/kataras/iris/v12 => C:/github/iris-private

Then run just that pairing: server-benchmarks run -t "static.iris (next)".

Run with Docker

The image bundles Go, Node.js, the .NET SDK and bombardier, so the full suite runs without installing anything else:

docker build -t server-benchmarks .
docker run --rm -v ${PWD}:/data server-benchmarks

Reports land in the mounted directory. ${PWD} works in both PowerShell and Unix shells.

Results

Results are machine-generated per run and depend heavily on the hardware. A fresh official run with the current roster has not been published yet; run the suite yourself, or expand the section below for the last published numbers.

Historical results (previous roster, Jun 20, 2022)

These numbers predate the current roster (they include Martini and Buffalo, since removed, and the Kestrel app replaced by ASP.NET Core minimal APIs) and ran on Go 1.19beta1, .NET 6 and Node 18 with different request counts.

System

ProcessorAMD Ryzen 9 4900HS with Radeon Graphics
RAM15.42 GB
OSMicrosoft Windows 11 Pro
Bombardierv1.2.4
Gogo1.19beta1
.NET6.0.300
Node.jsv18.2.0

Test: Static

๐Ÿ“– Fires 1000000 requests, receives a static message as response.

NameLanguageReqs/secLatencyThroughputTime To Complete
IrisGo284059438.34us49.58MB3.52s
ChiGo275525451.01us48.18MB3.62s
EchoGo267815466.16us46.64MB3.74s
KestrelC#263479472.72us44.68MB3.80s
GinGo263399472.70us45.98MB3.80s
MartiniGo233051534.43us40.68MB4.29s
KoaJavascript1312740.93ms29.24MB7.50s
BuffaloGo789631.58ms13.78MB12.66s
ExpressJavascript410783.02ms11.54MB24.22s

Test: Parameterized

๐Ÿ“– Fires 550000 requests with a dynamic parameter of string, receives a hello text based on the parameter as response.

NameLanguageReqs/secLatencyThroughputTime To Complete
IrisGo277099449.55us53.07MB1.99s
ChiGo272434456.62us52.21MB2.02s
EchoGo261467476.01us50.14MB2.10s
GinGo259308480.32us49.70MB2.12s
KestrelC#233843534.73us43.34MB2.36s
MartiniGo225790551.37us43.29MB2.44s
KoaJavascript1146671.08ms27.21MB4.78s
BuffaloGo767471.63ms14.71MB7.17s
ExpressJavascript371103.32ms11.11MB14.69s

Test: REST

๐Ÿ“– Fires 200000 requests with a dynamic parameter of int, sends JSON as request body and receives JSON as response.

NameLanguageReqs/secLatencyThroughputTime To Complete
IrisGo238954521.69us64.15MB0.84s
GinGo229665541.96us62.86MB0.87s
ChiGo228072545.78us62.61MB0.88s
EchoGo224491553.84us61.70MB0.89s
MartiniGo198166627.46us54.47MB1.01s
KestrelC#163486766.90us47.42MB1.23s
BuffaloGo1024781.22ms28.14MB1.95s
KoaJavascript484252.56ms15.39MB4.14s
ExpressJavascript236225.25ms9.04MB8.41s

Terminology

Name is the name of the framework (or router) used under a particular test.

Reqs/sec is the average number of requests processed per second (the higher the better).

Latency is the time from when a request is made by the client until the response gets back to that client (the lower the better).

Throughput is the rate at which data is transferred (the higher the better; it depends on the response length, body plus headers).

Time To Complete is the total time the test took to complete (the lower the better).

Contributing

Want a framework added? Read CONTRIBUTING.md; it takes one app directory per test and one entry in tests.yml.

License

This project is licensed under the MIT License.