Complete benchmark · 27 October 2026

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
Test hostGitHub Actions

Free Ubuntu 24.04 runners. Each HTTP repetition runs all five proxies on one host.

CPU budget2 logical CPUs

Two assigned CPUs and a 2-CPU quota, shared by proxy, app, load generator, and sampler.

Memory limit8 GiB RAM

No swap. Measured proxy memory excludes the app and load generator.

RuntimeUbuntu 26.04

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.

Tako at c50005.9k HTTP 200 RPS

3,798–9,694 across three runs.

Tako at c200002.9k HTTP 200 RPS

100% complete 200 outcomes on average.

Tako memory at c200001,343 MiB PSS

Mean peak proxy memory during those same throughput runs.

Features at c80002.3k publish / 2.2k enqueue

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.

05k10k15kc1kc2.5kc5kc7.5kc10kc15kc20knginx c1000: 12knginx c2500: 9.6knginx c5000: 8.5knginx c7500: 8.4knginx c10000: 7.7knginx c15000: 6.2knginx c20000: 6kHAProxy c1000: 11kHAProxy c2500: 9.7kHAProxy c5000: 8.4kHAProxy c7500: 8.2kHAProxy c10000: 7.4kHAProxy c15000: 6.3kHAProxy c20000: 4.8kTako c1000: 7.2kTako c2500: 6.5kTako c5000: 5.9kTako c7500: 5.1kTako c10000: 4.6kTako c15000: 3.9kTako c20000: 2.9kEnvoy c1000: 8.1kEnvoy c2500: 7.2kEnvoy c5000: 6.7kEnvoy c7500: 6.1kEnvoy c10000: 5.6kEnvoy c15000: 4.6kEnvoy c20000: 3.6kCaddy c1000: 4.1kCaddy c2500: 3.6kCaddy c5000: 3.2kCaddy c7500: 2.7kCaddy c10000: 2.2kCaddy c15000: 1.6kCaddy c20000: 1.4k
  • 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.

0ms10s20s30s40sc1kc2.5kc5kc7.5kc10kc15kc20knginx c1000: 250.8msnginx c2500: 602.6msnginx c5000: 1.7snginx c7500: 2.1snginx c10000: 2.8snginx c15000: 9.3snginx c20000: 8.6sHAProxy c1000: 209.6msHAProxy c2500: 2.8sHAProxy c5000: 7.6sHAProxy c7500: 13sHAProxy c10000: 17sHAProxy c15000: 22sHAProxy c20000: 31sTako c1000: 333.4msTako c2500: 2.3sTako c5000: 6.1sTako c7500: 10sTako c10000: 14sTako c15000: 16sTako c20000: 26sEnvoy c1000: 241.9msEnvoy c2500: 1.9sEnvoy c5000: 4.8sEnvoy c7500: 7.2sEnvoy c10000: 10sEnvoy c15000: 15sEnvoy c20000: 21sCaddy c1000: 1.2sCaddy c2500: 4.1sCaddy c5000: 8.1sCaddy c7500: 13sCaddy c10000: 13sCaddy c15000: 20sCaddy c20000: 25s
  • 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.

0%1%2%3%4%c1kc2.5kc5kc7.5kc10kc15kc20knginx c1000: 0%nginx c2500: 0%nginx c5000: 0%nginx c7500: 0%nginx c10000: 0%nginx c15000: 0.1%nginx c20000: 0.35%HAProxy c1000: 0%HAProxy c2500: 0%HAProxy c5000: 0%HAProxy c7500: 0%HAProxy c10000: 0%HAProxy c15000: 0%HAProxy c20000: 0%Tako c1000: 0%Tako c2500: 0%Tako c5000: 0%Tako c7500: 0%Tako c10000: 0%Tako c15000: 0%Tako c20000: 0%Envoy c1000: 0%Envoy c2500: 0%Envoy c5000: 0%Envoy c7500: 0%Envoy c10000: 0%Envoy c15000: 2.4%Envoy c20000: 0.75%Caddy c1000: 0%Caddy c2500: 0%Caddy c5000: 0.72%Caddy c7500: 1.75%Caddy c10000: 0.59%Caddy c15000: 3.8%Caddy c20000: 0%
  • 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.

0MiB500MiB1000MiB1.5GiB2GiBc1kc2.5kc5kc7.5kc10kc15kc20knginx c1000: 67MiBnginx c2500: 103.4MiBnginx c5000: 199.7MiBnginx c7500: 217MiBnginx c10000: 250.4MiBnginx c15000: 495MiBnginx c20000: 495.7MiBHAProxy c1000: 113.9MiBHAProxy c2500: 203.5MiBHAProxy c5000: 333.8MiBHAProxy c7500: 495MiBHAProxy c10000: 617.5MiBHAProxy c15000: 813.5MiBHAProxy c20000: 1GiBTako c1000: 156.4MiBTako c2500: 291MiBTako c5000: 504MiBTako c7500: 683.2MiBTako c10000: 864.8MiBTako c15000: 917MiBTako c20000: 1.3GiBEnvoy c1000: 125MiBEnvoy c2500: 205.9MiBEnvoy c5000: 339.7MiBEnvoy c7500: 473.1MiBEnvoy c10000: 600.7MiBEnvoy c15000: 833.8MiBEnvoy c20000: 1GiBCaddy c1000: 273.8MiBCaddy c2500: 483.9MiBCaddy c5000: 823.6MiBCaddy c7500: 1.2GiBCaddy c10000: 1.3GiBCaddy c15000: 1.5GiBCaddy c20000: 1.3GiB
  • 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.

0%20%40%60%80%c1kc2.5kc5kc7.5kc10kc15kc20knginx c1000: 31.07%nginx c2500: 34.05%nginx c5000: 35.11%nginx c7500: 35.44%nginx c10000: 34.98%nginx c15000: 39.03%nginx c20000: 37.92%HAProxy c1000: 37.35%HAProxy c2500: 38.25%HAProxy c5000: 41.01%HAProxy c7500: 43.08%HAProxy c10000: 45.05%HAProxy c15000: 48.43%HAProxy c20000: 52.93%Tako c1000: 49.92%Tako c2500: 50.82%Tako c5000: 53.86%Tako c7500: 54.98%Tako c10000: 55.89%Tako c15000: 57.45%Tako c20000: 59.72%Envoy c1000: 50.9%Envoy c2500: 52.01%Envoy c5000: 53.53%Envoy c7500: 55.46%Envoy c10000: 56.12%Envoy c15000: 57.59%Envoy c20000: 59.22%Caddy c1000: 51.26%Caddy c2500: 53.52%Caddy c5000: 57.08%Caddy c7500: 58.54%Caddy c10000: 62.9%Caddy c15000: 66.07%Caddy c20000: 69.81%
  • nginx
  • HAProxy
  • Tako
  • Envoy
  • Caddy

Scroll tables sideways to compare all columns.

Successful HTTPS responses per second. Secondary labels show complete 200 outcomes as a percentage of all attempts.
proxyc5000 RPSc10000 RPSc20000 RPSc20000 p99c20000 range
nginx8,467100% 2007,732100% 2005,98999.65% 2008,572 ms3,920–9,201 RPS
HAProxy8,406100% 2007,351100% 2004,764100% 20030,820 ms2,729–8,712 RPS
Tako5,850100% 2004,610100% 2002,877100% 20026,454 ms852–6,490 RPS
Envoy6,682100% 2005,570100% 2003,62199.25% 20021,357 ms1,938–6,915 RPS
Caddy3,24099.28% 2002,23899.41% 2001,359100% 20025,118 ms828–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.

Mean peak proxy PSS from the same HTTPS runs, in MiB. Lower is better when successful outcomes are comparable.
proxyc5000 MiBc10000 MiBc20000 MiBc20000 200c20000 PSS range
nginx199.7250.4495.799.65%218.5–711.9 MiB
HAProxy333.8617.51,048.1100%966–1,205.2 MiB
Tako504864.81,342.8100%921.6–1,619.5 MiB
Envoy339.7600.71,042.999.25%999.8–1,067.6 MiB
Caddy823.61,2871,372.7100%1,080.7–1,869 MiB
CPU distribution at c20000, as a percentage of the shared two-CPU budget. Means across three runs.
proxyproxy CPUapp CPUloadgen CPUtotal CPUapp PSS
nginx37.9%26%31.8%99.1%161 MiB
HAProxy52.9%15.7%28.1%99.8%141.4 MiB
Tako59.7%11.2%24.1%99.7%346.4 MiB
Envoy59.2%10.6%26%99.7%478.8 MiB
Caddy69.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.

01k2k3k4kc500c1kc2kc4kc8kChannel publish c500: 3.2kChannel publish c1000: 3.2kChannel publish c2000: 3kChannel publish c4000: 2.8kChannel publish c8000: 2.3kWorkflow enqueue c500: 3.3kWorkflow enqueue c1000: 3.1kWorkflow enqueue c2000: 3kWorkflow enqueue c4000: 2.7kWorkflow enqueue c8000: 2.2k
  • Channel publish
  • Workflow enqueue

Channels and workflows p99 latency

Mean p99 time to response headers across three fresh runs at each concurrency.

0ms5s10s15sc500c1kc2kc4kc8kChannel publish c500: 280.5msChannel publish c1000: 1sChannel publish c2000: 2.5sChannel publish c4000: 5.9sChannel publish c8000: 12sWorkflow enqueue c500: 255.2msWorkflow enqueue c1000: 1.1sWorkflow enqueue c2000: 2.7sWorkflow enqueue c4000: 6.2sWorkflow enqueue c8000: 14s
  • Channel publish
  • Workflow enqueue

Feature errors

Non-200 responses plus client errors as a percentage of attempts. Every repetition is included.

0%0.25%0.5%0.75%1%c500c1kc2kc4kc8kChannel publish c500: 0%Channel publish c1000: 0%Channel publish c2000: 0%Channel publish c4000: 0%Channel publish c8000: 0%Workflow enqueue c500: 0%Workflow enqueue c1000: 0%Workflow enqueue c2000: 0%Workflow enqueue c4000: 0%Workflow enqueue c8000: 0.28%
  • 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.

0MiB250MiB500MiB750MiB1000MiBc500c1kc2kc4kc8kChannel publish c500: 173.7MiBChannel publish c1000: 213.4MiBChannel publish c2000: 287.6MiBChannel publish c4000: 476.1MiBChannel publish c8000: 842.5MiBWorkflow enqueue c500: 190.3MiBWorkflow enqueue c1000: 222.7MiBWorkflow enqueue c2000: 312.4MiBWorkflow enqueue c4000: 529.8MiBWorkflow enqueue c8000: 902.6MiB
  • Channel publish
  • Workflow enqueue
Feature results at c8000. Rates, latency, and memory are means; error counts are totals across three runs. Enqueue RPS measures acceptance, not completed workflows.
operation200 RPSp99200 outcomesclient errors (total)app / worker PSS
Channel publish2,33412,438 ms100%0109.2 MiB
Workflow enqueue2,16513,687 ms99.72%0135.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.

Timing and transport

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.

Measurement

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.

Reproducible builds

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.

Measured software versions
softwareversion
nginxnginx version: nginx/1.28.3 (Ubuntu)
HAProxyHAProxy version 3.2.25-0ubuntu0.26.04.1 2026/09/24 - https://haproxy.org/
Envoyenvoy version: f1dd21b16c244bda00edfb5ffce577e12d0d2ec2/1.38.0/Clean/RELEASE/BoringSSL
Takotako-server 0.0.0
Caddyv2.11.7 h1:yj0Y4fYZGPkSvibBJ1sTWE33xC0fxztVyXEW5iIdUT4=
bun1.4.4
opensslOpenSSL 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.