oha: HTTP Load Testing with a Live TUI
oha -n <requests> -c <connections> <url> generates HTTP load and shows a live latency histogram, with a JSON summary mode for CI.
oha is a hey-style load tester written in Rust with a real-time TUI. In CI you disable the TUI and read its summary, which it can emit as JSON for assertions.
What it does
oha sends -n requests across -c connections (or for -z duration), rendering a live histogram and slowest/fastest stats. With --no-tui it prints a plain summary on exit, and -j / --output-format json emits a machine-readable result for gating.
Common usage
oha -n 5000 -c 50 https://staging.example.com/
# duration mode, no TUI, JSON for CI assertions
oha -z 30s -c 100 --no-tui -j https://staging.example.com/ \
> oha.json
# limit requests per second
oha -q 200 -z 1m --no-tui https://staging.example.com/Options
| Flag | What it does |
|---|---|
| -n <num> | Total number of requests |
| -c <num> | Number of concurrent connections |
| -z <dur> | Run for a duration instead of -n |
| -q <qps> | Cap requests per second |
| --no-tui | Disable the live UI (use in CI) |
| -j, --output-format json | Emit a JSON summary |
In CI
Always pass --no-tui in pipelines; the TUI assumes an interactive terminal and clutters logs otherwise. Capture -j JSON and assert on summary.successRate and the latency percentiles with jq, failing the step when an SLO is missed.
Common errors in CI
Without --no-tui you may see garbled terminal escape sequences or "No such device or address" on a runner with no TTY; add --no-tui. "error sending request ... connection refused" means the target is down. "invalid peer certificate" on a self-signed staging endpoint is fixed with --insecure (oha supports it, unlike hey).