h2load — HTTP/2 Load Testing on the Command Line
Practical guide to h2load — HTTP/2 and HTTP/1.1 load tests with concurrent streams, TLS, rate control and experimental HTTP/3 (QUIC).
h2load is the benchmarking and load-testing tool from the nghttp2 project: it measures server throughput and latency under HTTP/2 and HTTP/1.1 load, using real concurrent streams just as a browser would send them. A handful of flags let you fire a hundred thousand requests from a hundred parallel clients, control the connection rate, switch between TLS and cleartext, and read the results straight from the compact summary output.
Basic Usage
h2load <url> — Send a single request to the given URL (default: 1 request, 1 client).
h2load https://localhost:8443/h2load -n <requests> -c <clients> -m <streams> <url> — Run a benchmark with N total requests, C concurrent clients, and M max concurrent streams per session.
h2load -n100000 -c100 -m10 https://localhost:8443/h2load -n <requests> -c <clients> -t <threads> <url> — Use multiple native threads. Useful when the benchmark client itself becomes a bottleneck.
h2load -n100000 -c100 -t4 https://localhost:8443/h2load -n <requests> -c <clients> -m <streams> -t <threads> <url> — Full benchmark with threads, clients, and concurrent streams.
h2load -n1000000 -c200 -m50 -t8 https://localhost:8443/Duration-Based Benchmarking
h2load -c <clients> -m <streams> -D <duration> <url> — Run for a fixed duration instead of a fixed number of requests. The -n option is ignored.
h2load -c100 -m10 -D 30s https://localhost:8443/h2load -c <clients> -m <streams> -D <duration> --warm-up-time=<duration> <url> — Run with a warm-up period before actual measurement begins. Requires -D.
h2load -c100 -m100 -D 60s --warm-up-time=5s https://localhost:8443/Rate Control
h2load -n <requests> -c <clients> -r <rate> <url> — Create connections at a fixed rate per second. Distributed evenly among threads. Mutually exclusive with -D.
h2load -n10000 -c100 -r4 -t2 https://localhost:8443/h2load -n <requests> -c <clients> -r <rate> --rate-period=<duration> <url> — Create connections at a fixed rate per custom time period.
h2load -n10000 -c100 -r10 --rate-period=500ms https://localhost:8443/h2load -n <requests> -c <clients> --rps=<N> <url> — Limit requests per second for each client. Mutually exclusive with --timing-script-file.
h2load -n10000 -c10 --rps=100 https://localhost:8443/Protocol Selection
h2load --h1 <url> — Force HTTP/1.1 for both TLS and cleartext connections.
h2load -n1000 -c10 --h1 https://localhost:8443/h2load -p h2c <url> — Use HTTP/2 cleartext (h2c) for non-TLS connections. This is the default.
h2load -n1000 -c10 -p h2c http://localhost:8080/h2load -p http/1.1 <url> — Use HTTP/1.1 for cleartext connections.
h2load -n1000 -c10 -p http/1.1 http://localhost:8080/h2load --alpn-list=<protocols> <url> — Set ALPN protocol list for TLS negotiation in preference order.
h2load -n1000 -c10 --alpn-list=h2,http/1.1 https://localhost:8443/h2load --alpn-list=h3 <url> — Use HTTP/3 (QUIC). Experimental, requires h2load built with QUIC support.
h2load -n1000 -c10 --alpn-list=h3 https://localhost:443/Headers & POST Data
h2load -H '<header>' <url> — Add or override an HTTP header. Can be specified multiple times.
h2load -n1000 -c10 -H 'Authorization: Bearer token123' https://localhost:8443/apih2load -H '<h1>' -H '<h2>' <url> — Add multiple custom headers.
h2load -n1000 -c10 -H 'Accept: application/json' -H 'X-API-Key: abc123' https://localhost:8443/apih2load -d <path> <url> — POST file contents to the server. Changes the request method to POST.
h2load -n1000 -c10 -d /tmp/payload.json -H 'Content-Type: application/json' https://localhost:8443/apiURI Input & Scripting
h2load <url1> <url2> <url3> — Benchmark multiple URIs in round-robin order. Only the first URI's scheme, host, and port are used.
h2load -n10000 -c50 https://localhost:8443/ https://localhost:8443/api https://localhost:8443/healthh2load -i <file> <url> — Read URIs from a file (one per line). Use - for stdin. Disables command-line URIs.
h2load -n10000 -c50 -i urls.txt https://localhost:8443/h2load --timing-script-file=<file> — Replay timed request scripts. Each line: millisecond_offset
h2load -c10 --timing-script-file=script.txth2load -B <base_uri> -i <file> — Override scheme, host, and port for all URIs from input file.
h2load -n10000 -c50 -B https://staging.example.com -i urls.txth2load -B unix:<path> <url> — Connect via UNIX domain socket.
h2load -n1000 -c10 -B unix:/tmp/nghttpx.sock http://localhost/Connection & Timeout
h2load -T <duration> <url> — Set maximum connection active timeout regardless of activity.
h2load -n1000 -c10 -T 30s https://localhost:8443/h2load -N <duration> <url> — Set maximum connection inactivity timeout.
h2load -n1000 -c10 -N 10s https://localhost:8443/h2load --connect-to=<host>:<port> <url> — Connect to a different host:port than specified in the URI.
h2load -n1000 --connect-to=127.0.0.1:8443 https://example.com/HTTP/2 Flow Control
h2load -w <bits> -W <bits> <url> — Set stream-level (-w) and connection-level (-W) initial window size as (2^N)-1 bytes. Default: 30 (very large).
h2load -n100000 -c100 -m10 -w16 -W16 https://localhost:8443/h2load -f <size> <url> — Set the maximum HTTP/2 frame size the local endpoint is willing to receive.
h2load -n10000 -c50 -f 32K https://localhost:8443/h2load --header-table-size=<size> <url> — Set HPACK decoder header table size.
h2load -n10000 -c50 --header-table-size=8K https://localhost:8443/h2load --encoder-header-table-size=<size> <url> — Set HPACK encoder header table size.
h2load -n10000 -c50 --encoder-header-table-size=8K https://localhost:8443/TLS Configuration
h2load --ciphers=<suite> <url> — Set allowed cipher list for TLSv1.2 or earlier (OpenSSL format).
h2load -n1000 -c10 --ciphers=ECDHE-RSA-AES128-GCM-SHA256 https://localhost:8443/h2load --tls13-ciphers=<suite> <url> — Set allowed cipher list for TLSv1.3 (OpenSSL format).
h2load -n1000 -c10 --tls13-ciphers=TLS_AES_256_GCM_SHA384 https://localhost:8443/h2load --groups=<groups> <url> — Set supported TLS groups (key exchange).
h2load -n1000 -c10 --groups=X25519:P-256 https://localhost:8443/h2load --sni=<dnsname> <url> — Send a custom DNS name in TLS SNI, overriding the host from the URI.
h2load -n1000 --sni=example.com https://127.0.0.1:8443/h2load --ktls <url> — Enable kernel TLS (kTLS) for potentially improved performance.
h2load -n100000 -c100 --ktls https://localhost:8443/Logging & Output
h2load -v <url> — Enable verbose debug output.
h2load -v -n10 -c1 https://localhost:8443/h2load --log-file=<path> <url> — Write per-request log (tab-separated: start time in µs, HTTP status, response time in µs). Status -1 for failed streams.
h2load -n10000 -c50 --log-file=/tmp/h2load.log https://localhost:8443/h2load --qlog-file-base=<path> <url> — Enable qlog output for QUIC connections. Files are named base.M.N.sqlog (M=worker, N=client).
h2load -n1000 -c10 --alpn-list=h3 --qlog-file-base=/tmp/qlog https://localhost:443/Common Patterns
h2load -n100000 -c100 -m10 <url> — Standard HTTP/2 benchmark: 100K requests, 100 clients, 10 concurrent streams.
h2load -n100000 -c100 -m10 https://localhost:8443/h2load -c100 -m100 -D 60s --warm-up-time=5s <url> — Duration-based test with warm-up phase for stable measurements.
h2load -c100 -m100 -D 60s --warm-up-time=5s https://localhost:8443/h2load -n10000 -c10 --h1 <url> — Compare HTTP/1.1 performance against HTTP/2 baseline.
h2load -n10000 -c10 --h1 https://localhost:8443/h2load -n100000 -c100 -m10 -w16 -W16 <url> — Benchmark with HTTP/2 spec-default flow control windows (64K) instead of the large defaults.
h2load -n100000 -c100 -m10 -w16 -W16 https://localhost:8443/for c in 10 50 100 500; do echo "--- $c clients ---"; h2load -n10000 -c$c -m10 <url>; done — Progressive load test at increasing concurrency levels.
for c in 10 50 100 500; do echo "--- $c clients ---"; h2load -n10000 -c$c -m10 https://localhost:8443/; doneh2load -c1 -m1 -n1 -v <url> — Single request with verbose output for debugging connection and protocol negotiation.
h2load -c1 -m1 -n1 -v https://localhost:8443/Unit Conventions
h2load -D 30s / -D 1m / -D 500ms — Duration units: s=seconds, m=minutes, h=hours, ms=milliseconds. Default (no unit) is seconds.
h2load -f 16K / -f 1M / -f 1G — Size units: K=1024, M=1024², G=1024³. Used for frame size, header table size, and UDP payload size.
Conclusion
h2load is the go-to tool when you need reliable HTTP/2 performance numbers: the combination of concurrent streams, threads, and fine-grained TLS control models real browser load far better than classic tools. Start with the standard profile (-n100000 -c100 -m10) and tune clients and streams until you find your server's ceiling.
Further Reading
- nghttp2 – official documentation – h2load reference and full nghttp2 project docs
- h2load – how-to guide – step-by-step walkthrough and option overview