# 📊 Benchmarks

This page compares throughput under a controlled workload and documents the
versions, environment, and measurement conditions.

## 🧭 How the comparison was run

- **Versions.** Pingclair `v0.2.0-rc.3`, measured from that release candidate's
  binary, nginx 1.31.6, and Caddy 2.11.4. Later patch releases are not
  re-measured.
- **Host.** One Apple M2 laptop running OrbStack.
- **Limits.** Every server runs in a container capped at two CPUs, with the
  same worker count and the same 1 KiB payload.
- **Topology.** The reverse-proxy backend runs in its own container on the same
  Docker network.
- **Load generator.** HTTP/1.1, HTTPS/1.1, and HTTP/2 use a native `h2load`.
  HTTP/3 uses an ngtcp2-enabled `h2load` inside the same Docker network.

## 📊 Results

Each value is requests per second: the median of three interleaved rounds of
50,000 requests. A row counts only when every request succeeded.

| Scenario | Pingclair | nginx 1.31.6 | Caddy 2.11.4 |
| --- | ---: | ---: | ---: |
| HTTP/1.1 static | 46,125 | 39,478 | 18,266 |
| HTTPS/1.1 static | 40,721 | 31,508 | 19,978 |
| HTTP/2 static | 92,369 | 41,972 | 17,424 |
| HTTP/3 static | 56,180 | 55,638 | 22,912 |
| HTTP/1.1 reverse proxy | 20,856 | 22,584 | 17,117 |
| HTTPS/1.1 reverse proxy | 20,297 | 21,944 | 16,660 |
| HTTP/2 reverse proxy | 23,181 | 20,396 | not completed |
| HTTP/3 reverse proxy | 28,078 | 22,213 | not completed |

Against nginx, Pingclair has higher throughput in the
HTTP/1.1, HTTPS/1.1, and HTTP/2 static rows (1.2x, 1.3x, and 2.2x
respectively), while HTTP/3 static throughput is approximately equal. On the reverse-proxy
workload it is 14% ahead on HTTP/2 and 26% ahead on HTTP/3, while HTTP/1.1 and
HTTPS/1.1 remain about 8% behind nginx.

## 📐 Conditions that limit these numbers

- **The host is a laptop.** Absolute throughput is not a capacity claim, and the ratios describe relative
  performance under this controlled workload only.
- **Compare within a row.** The HTTP/3 load generator runs in a different
  environment from the others, so absolute throughput should not be compared across
  protocols, only between servers within a row.
- **Incomplete rows are not comparisons.** On this host and harness, Caddy did
  not complete the proxied HTTP/2 and HTTP/3 rows: upstream connection churn
  exhausted the container's available ephemeral ports at the tested
  concurrency. Those cells are reported as incomplete rather than measured
  under a different workload.
- **The results are host-dependent.** The relative position of the servers
  changes with CPU architecture, kernel, worker count, and TLS implementation.

## 🧾 Source

The numbers come from one run of the server repository's benchmark harness. The
methodology, the rules a run must meet before a number counts, and the harness
are published there:

- [Benchmark methodology](https://github.com/dorianverlaine/pingclair/blob/main/benchmarks/README.md)

Raw per-run evidence stays in the maintainer's checkout and is not published.
