Serious load, measured in public.
Tako, nginx, HAProxy, Envoy, and Caddy under the same HTTPS load. Every chart below comes from this benchmark suite: 105 proxy runs and 30 channel and workflow runs, with three repetitions at every point.
All Tako HTTP runs completed cleanly. At 5,000 concurrent clients, Tako averaged 5.9k complete 200 responses per second; nginx led this row at8.5k. All five proxies’ latency, memory, and errors stay beside their throughput.
- largest HTTP load
- c20000
- Tako non-200
- 0
- Tako client errors
- 0
Free Ubuntu 24.04 runners. Each HTTP repetition runs all five proxies on one host.
Two assigned CPUs and a 2-CPU quota, shared by proxy, app, load generator, and sampler.
No swap. Measured proxy memory excludes the app and load generator.
One identical container image across all six measurement jobs.
Runner CPU models: AMD EPYC 9V45 96-Core Processor; AMD EPYC 7763 64-Core Processor; AMD EPYC 9V74 80-Core Processor. Linux kernels: 6.17.0-1022-azure. This is a new hardware baseline; these numbers are not directly comparable with the archived VM runs.
3,798–9,694 across three runs.
100% complete 200 outcomes on average.
Mean peak proxy memory during those same throughput runs.
Successful HTTP requests per second, measured separately.
What these results show
Tako was faster than Caddy at every tested concurrency, while nginx, HAProxy, and Envoy delivered higher successful throughput. Tako and HAProxy returned all 200 responses across their HTTP runs. Memory remains a substantial cost: Tako used 1,343 MiB peak PSS on average at c20000.
All 135 runs are included; 122 completed without HTTP or client errors. Two nginx c15000 runs had 24 and 23 resource samples, below the planned minimum of 25, so their memory peaks may be undersampled. One load-generator CPU measurement at Tako c15000 was invalid after the process exited; that aggregate is marked unavailable in the full report. The other measurements were checked independently.
The complete HTTPS comparison#
Same route, RSA certificate, Go upstream app, load generator, and configured request and connection limits documented in the report. Each point is the mean of three fresh runs. Proxy order rotates across repetitions; the report retains every individual run and its range.
HTTP 200 responses per second
Mean of three runs. Only complete 200 responses count; elapsed time includes request drain.
- nginx
- HAProxy
- Tako
- Envoy
- Caddy
p99 response latency
Mean of each run’s p99 time to response headers. Read alongside errors: failed requests do not contribute latency samples.
- nginx
- HAProxy
- Tako
- Envoy
- Caddy
Non-200 responses and client errors
Percentage of attempted outcomes that did not complete with HTTP 200. Lower is better; no failed runs are omitted.
- nginx
- HAProxy
- Tako
- Envoy
- Caddy
Proxy memory under load
Mean of each run’s peak process PSS, sampled during the same load as throughput. Includes all proxy workers; excludes app, load generator, and kernel socket memory.
- nginx
- HAProxy
- Tako
- Envoy
- Caddy
Proxy CPU usage
Mean process CPU as a percentage of the shared two-CPU budget. 100% means both assigned CPUs are fully used.
- nginx
- HAProxy
- Tako
- Envoy
- Caddy
Scroll tables sideways to compare all columns.
| proxy | c5000 RPS | c10000 RPS | c20000 RPS | c20000 p99 | c20000 range |
|---|---|---|---|---|---|
| nginx | 8,467100% 200 | 7,732100% 200 | 5,98999.65% 200 | 8,572 ms | 3,920–9,201 RPS |
| HAProxy | 8,406100% 200 | 7,351100% 200 | 4,764100% 200 | 30,820 ms | 2,729–8,712 RPS |
| Tako | 5,850100% 200 | 4,610100% 200 | 2,877100% 200 | 26,454 ms | 852–6,490 RPS |
| Envoy | 6,682100% 200 | 5,570100% 200 | 3,62199.25% 200 | 21,357 ms | 1,938–6,915 RPS |
| Caddy | 3,24099.28% 200 | 2,23899.41% 200 | 1,359100% 200 | 25,118 ms | 828–2,397 RPS |
Memory under the same load#
Memory is process PSS, which apportions shared pages instead of counting them twice. These values are the mean of each run’s peak during measurement, including request drain. Compare memory with successful outcomes: a proxy that rejects or times out requests is not serving equivalent load.
| proxy | c5000 MiB | c10000 MiB | c20000 MiB | c20000 200 | c20000 PSS range |
|---|---|---|---|---|---|
| nginx | 199.7 | 250.4 | 495.7 | 99.65% | 218.5–711.9 MiB |
| HAProxy | 333.8 | 617.5 | 1,048.1 | 100% | 966–1,205.2 MiB |
| Tako | 504 | 864.8 | 1,342.8 | 100% | 921.6–1,619.5 MiB |
| Envoy | 339.7 | 600.7 | 1,042.9 | 99.25% | 999.8–1,067.6 MiB |
| Caddy | 823.6 | 1,287 | 1,372.7 | 100% | 1,080.7–1,869 MiB |
| proxy | proxy CPU | app CPU | loadgen CPU | total CPU | app PSS |
|---|---|---|---|---|---|
| nginx | 37.9% | 26% | 31.8% | 99.1% | 161 MiB |
| HAProxy | 52.9% | 15.7% | 28.1% | 99.8% | 141.4 MiB |
| Tako | 59.7% | 11.2% | 24.1% | 99.7% | 346.4 MiB |
| Envoy | 59.2% | 10.6% | 26% | 99.7% | 478.8 MiB |
| Caddy | 69.8% | 11% | 14.6% | 99.7% | 308.6 MiB |
Channels and workflows#
These are the same feature operations as the original benchmark, rerun with the current server and SDK. Each runs in a real deployed application, with the same two-CPU and 8 GiB limits. Channel publish writes one durable message; workflow enqueue accepts a task whose handler persists one ack step.
Channels and workflows 200 RPS
The original JavaScript workload: publish a durable channel message or enqueue a workflow whose handler persists one ack step. This measures HTTP acceptance, not workflow completion throughput.
- Channel publish
- Workflow enqueue
Channels and workflows p99 latency
Mean p99 time to response headers across three fresh runs at each concurrency.
- Channel publish
- Workflow enqueue
Feature errors
Non-200 responses plus client errors as a percentage of attempts. Every repetition is included.
- Channel publish
- Workflow enqueue
Feature proxy memory
Mean peak process PSS for the Tako server. Application and workflow workers are measured separately in the raw results.
- Channel publish
- Workflow enqueue
| operation | 200 RPS | p99 | 200 outcomes | client errors (total) | app / worker PSS |
|---|---|---|---|---|---|
| Channel publish | 2,334 | 12,438 ms | 100% | 0 | 109.2 MiB |
| Workflow enqueue | 2,165 | 13,687 ms | 99.72% | 0 | 135.1 MiB |
Same conditions, public raw data.#
All 135 measurements are included. Results are generated from validated raw JSON, and the complete dataset, configurations, build identities, and workflow are public.
HTTP/1.1 over TLS; 10-second warmup, 30-second measurement, 60-second per-request timeout, 16 loopback source addresses, and a 10-second cooldown. RPS includes request drain. Latency measures time to response headers; errors remain visible separately.
Backend apps and workflow workers use matching 65,535-file descriptor limits, verified during measurement. Tako’s production app default is 4,096; this high-concurrency benchmark configures the higher app limit. One-second process and cgroup samples. nginx memory includes master and worker processes. App and workflow workers are separate from Tako’s proxy totals. PSS excludes kernel socket memory. Chart points are means of three per-run values, not pooled latency percentiles.
Tako server and SDK: 1093899fd6b0. All jobs use identical binaries and one runtime image. The full report records hashes and pinned sources. Worker counts and Go parallelism are set to two.
| software | version |
|---|---|
| nginx | nginx version: nginx/1.28.3 (Ubuntu) |
| HAProxy | HAProxy version 3.2.25-0ubuntu0.26.04.1 2026/09/24 - https://haproxy.org/ |
| Envoy | envoy version: f1dd21b16c244bda00edfb5ffce577e12d0d2ec2/1.38.0/Clean/RELEASE/BoringSSL |
| Tako | tako-server 0.0.0 |
| Caddy | v2.11.7 h1:yj0Y4fYZGPkSvibBJ1sTWE33xC0fxztVyXEW5iIdUT4= |
| bun | 1.4.4 |
| openssl | OpenSSL 3.5.5 27 Jan 2026 (Library: OpenSSL 3.5.5 27 Jan 2026) |
The load generator and backend share the test’s CPU budget with the proxy. This measures the complete setup under saturation, not an isolated proxy ceiling or a production capacity guarantee. Separate GitHub hosts can vary; the full report shows individual repetitions. Historical measurements remain archived in the performance repository.