Performance benchmarks comparing GraphQL gateway implementations across federation and composite schema approaches.
Latest Results: Constant Load | Constant Load with Latency | Burst Load
Each benchmark runs a gateway against 4 subgraphs (Accounts, Inventory, Products, Reviews) and executes a heavy nested query. There are three test categories, each designed to measure different aspects of gateway performance:
-
Constant Load (
constant) — 50 VUs for 120s. Simulates stable, sustained traffic against a gateway without any artificial latency on the subgraphs. Measures raw gateway throughput and how well it handles a steady request rate. -
Constant Load with Latency (
constant-latency) — 50 VUs for 120s, .NET subgraphs only. Simulates more realistic requests by adding a 4ms delay per subgraph HTTP request, accounting for the database or service calls that would normally happen inside a subgraph. Shows how gateways perform when subgraph response times are non-trivial. -
Burst (
burst) — 60s total, single burst from 50 to 500 VUs. Simulates a short, intense spike of traffic to see how gateways handle sudden load increases and recover afterward.
Subgraph variants:
subgraphs-rust= Rust (async-graphql+axum)subgraphs-net= .NET (HotChocolate)
Both benchmark families support both subgraph variants:
apollo-federation/*gateways can run with Rust or .NET subgraphscomposite-schema/*gateways can run with Rust or .NET subgraphs
- Apollo Gateway (Node.js)
- Apollo Router (Rust)
- Cosmo (Go)
- Grafbase (Rust)
- Hive Gateway (Node.js)
- Hive Gateway Router Runtime (Node.js)
- Hive Router (Rust)
- HotChocolate (.NET)
- k6
- jq - required by the monitor script
- python3 - used for JSON parsing
- curl - used for health checks
- bash, taskset (optional, Linux only for pinning)
- Gateway dependencies are handled by each gateway's
install.sh
./k6/benchmark.sh <gateway-path> [subgraphs-dir] [constant|constant-latency|burst|ramping]Examples:
# composite-schema + .NET subgraphs (default)
./k6/benchmark.sh composite-schema/gateways/hotchocolate
# composite-schema + Rust subgraphs
./k6/benchmark.sh composite-schema/gateways/hotchocolate subgraphs-rust
# apollo-federation + .NET subgraphs
./k6/benchmark.sh apollo-federation/gateways/apollo-router subgraphs-net
# burst mode
./k6/benchmark.sh apollo-federation/gateways/cosmo burst
# constant-latency mode (.NET subgraphs with simulated 4ms IO delay)
./k6/benchmark.sh apollo-federation/gateways/grafbase subgraphs-net constant-latency- Resolves subgraph directory (
subgraphs-rust/subgraphs-net) - Builds subgraphs (
subgraphs/build.sh) unlessUSE_PREBUILT_SUBGRAPHS=1 - Installs/builds gateway (
gateway/install.sh) unlessUSE_PREBUILT_GATEWAY=1 - Starts subgraphs and gateway (optionally CPU-pinned)
- Executes one full-duration warmup run (discarded)
- Executes measured runs (
BENCH_RUNS, default9) - Captures monitor + k6 summaries for each run
- Prints run statistics (median/mean/CV and CPU usage medians)
Environment variables:
| Variable | Default | Description |
|---|---|---|
MEASURE_SECONDS |
120 (constant) / 60 (burst) |
Benchmark measurement duration |
BENCH_RUNS |
9 |
Measured runs (plus one warmup run) |
BENCH_VUS |
50 constant / 500 burst |
VU target passed to k6/k6.js |
BENCH_DISPLAY_NAME |
(auto) | Override report display name |
BENCH_SUBGRAPH_TECH |
(auto) | Explicit subgraph tech label (rust / .net) |
USE_PREBUILT_SUBGRAPHS |
0 |
Skip build.sh and expect prebuilt subgraph artifact |
USE_PREBUILT_GATEWAY |
0 |
Skip install.sh and expect prebuilt gateway artifact |
On Linux with taskset, profiles.json is used to pin:
systemk6gatewaysubgraphs
Profile selection is based on logical core count (8 or 16 profile).
Each run produces a timestamped results directory:
<gateway-dir>/results/<timestamp>/
data.csv # monitor time series
metadata.json # gateway/subgraph/machine metadata
memory.json # idle/peak/end RSS + avg core usage (k6/subgraphs)
k6_summary.json # full k6 metrics (machine-readable)
k6_summary.txt # k6 summary (human-readable)
Workflow: benchmark.yml
- Triggers:
workflow_dispatch- scheduled daily at
21:00 UTC
- Dynamic matrix:
- Builds gateway matrix from selected input
- Expands each gateway into
rust+.netsubgraph variants
- Build stages on
ubuntu-latest:build-subgraphs(prebuilt artifacts)build-gateways(prebuilt artifacts)
- Benchmark stages on dedicated benchmark runner:
benchmark-constant-latency(.NET subgraphs only, 4ms simulated IO delay)benchmark-constant(runs after constant-latency completes)benchmark-burst(runs after constant completes)
- Result generation:
generate-results-constant-latencygenerate-results-constantgenerate-results-burst- final
benchmark-summaryjob publishes all result docs in the run summary
- Result documents are committed back to the branch by the generator jobs
This benchmark repository is based on the work by The Guild on graphql-gateways-benchmark.