# 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).

Source: https://www.jpkc.com/db/en/cheatsheets/networking/h2load/

<!-- PROSE:intro -->
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.
<!-- PROSE:intro:end -->

## Basic Usage

`h2load <url>` — Send a single request to the given URL (default: 1 request, 1 client).

```bash
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.

```bash
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.

```bash
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.

```bash
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.

```bash
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.

```bash
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.

```bash
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.

```bash
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.

```bash
h2load -n10000 -c10 --rps=100 https://localhost:8443/
```

## Protocol Selection

`h2load --h1 <url>` — Force HTTP/1.1 for both TLS and cleartext connections.

```bash
h2load -n1000 -c10 --h1 https://localhost:8443/
```

`h2load -p h2c <url>` — Use HTTP/2 cleartext (h2c) for non-TLS connections. This is the default.

```bash
h2load -n1000 -c10 -p h2c http://localhost:8080/
```

`h2load -p http/1.1 <url>` — Use HTTP/1.1 for cleartext connections.

```bash
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.

```bash
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.

```bash
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.

```bash
h2load -n1000 -c10 -H 'Authorization: Bearer token123' https://localhost:8443/api
```

`h2load -H '<h1>' -H '<h2>' <url>` — Add multiple custom headers.

```bash
h2load -n1000 -c10 -H 'Accept: application/json' -H 'X-API-Key: abc123' https://localhost:8443/api
```

`h2load -d <path> <url>` — POST file contents to the server. Changes the request method to POST.

```bash
h2load -n1000 -c10 -d /tmp/payload.json -H 'Content-Type: application/json' https://localhost:8443/api
```

## URI Input & Scripting

`h2load <url1> <url2> <url3>` — Benchmark multiple URIs in round-robin order. Only the first URI's scheme, host, and port are used.

```bash
h2load -n10000 -c50 https://localhost:8443/ https://localhost:8443/api https://localhost:8443/health
```

`h2load -i <file> <url>` — Read URIs from a file (one per line). Use - for stdin. Disables command-line URIs.

```bash
h2load -n10000 -c50 -i urls.txt https://localhost:8443/
```

`h2load --timing-script-file=<file>` — Replay timed request scripts. Each line: millisecond_offset<TAB>URI. With -n, requests become per-client.

```bash
h2load -c10 --timing-script-file=script.txt
```

`h2load -B <base_uri> -i <file>` — Override scheme, host, and port for all URIs from input file.

```bash
h2load -n10000 -c50 -B https://staging.example.com -i urls.txt
```

`h2load -B unix:<path> <url>` — Connect via UNIX domain socket.

```bash
h2load -n1000 -c10 -B unix:/tmp/nghttpx.sock http://localhost/
```

## Connection & Timeout

`h2load -T <duration> <url>` — Set maximum connection active timeout regardless of activity.

```bash
h2load -n1000 -c10 -T 30s https://localhost:8443/
```

`h2load -N <duration> <url>` — Set maximum connection inactivity timeout.

```bash
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.

```bash
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).

```bash
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.

```bash
h2load -n10000 -c50 -f 32K https://localhost:8443/
```

`h2load --header-table-size=<size> <url>` — Set HPACK decoder header table size.

```bash
h2load -n10000 -c50 --header-table-size=8K https://localhost:8443/
```

`h2load --encoder-header-table-size=<size> <url>` — Set HPACK encoder header table size.

```bash
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).

```bash
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).

```bash
h2load -n1000 -c10 --tls13-ciphers=TLS_AES_256_GCM_SHA384 https://localhost:8443/
```

`h2load --groups=<groups> <url>` — Set supported TLS groups (key exchange).

```bash
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.

```bash
h2load -n1000 --sni=example.com https://127.0.0.1:8443/
```

`h2load --ktls <url>` — Enable kernel TLS (kTLS) for potentially improved performance.

```bash
h2load -n100000 -c100 --ktls https://localhost:8443/
```

## Logging & Output

`h2load -v <url>` — Enable verbose debug output.

```bash
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.

```bash
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).

```bash
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.

```bash
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.

```bash
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.

```bash
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.

```bash
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.

```bash
for c in 10 50 100 500; do echo "--- $c clients ---"; h2load -n10000 -c$c -m10 https://localhost:8443/; done
```

`h2load -c1 -m1 -n1 -v <url>` — Single request with verbose output for debugging connection and protocol negotiation.

```bash
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.

<!-- PROSE:outro -->
## 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](https://nghttp2.org/documentation/) – h2load reference and full nghttp2 project docs
- [h2load – how-to guide](https://nghttp2.org/documentation/h2load-howto.html) – step-by-step walkthrough and option overview
<!-- PROSE:outro:end -->

## Related Commands

- [ab](https://www.jpkc.com/db/en/cheatsheets/networking/ab/) – classic Apache benchmark tool for quick HTTP load tests
- [wrk](https://www.jpkc.com/db/en/cheatsheets/networking/wrk/) – modern HTTP benchmark with Lua scripting support
- [siege](https://www.jpkc.com/db/en/cheatsheets/networking/siege/) – load and stress testing for web servers

