goperf is a lightweight, high-performance HTTP load testing and benchmarking tool written in Go. It focuses on closed-loop load testing to help developers quickly validate API performance, measure concurrency limits, and analyze real-world latency metrics like p90 and p99.
- Concurrency & Duration Testing: Test by a strict number of requests or over a sustained duration.
- Detailed Metrics: Accurate reporting of TTFB (Time To First Byte) latencies, including min, max, average, p50, p90, and p99 percentiles.
- Live Progress: Real-time updates every 2 seconds showing request count, throughput (req/s), and error count.
- Response Time Histogram: Visual distribution of response times to quickly spot latency patterns.
- Error Categorization: Automatic breakdown of network-level errors (timeouts, connection refused, DNS failures, etc.) alongside HTTP status code distribution.
- CI/CD Ready: Native JSON output support for easy integration into automated pipelines.
- Configurable: Support for complex requests via YAML/JSON configuration files.
Linux / macOS
curl -sL https://raw.githubusercontent.com/infraspecdev/goperf/main/install.sh | shWindows (PowerShell)
irm https://raw.githubusercontent.com/infraspecdev/goperf/main/install.ps1 | iexBuild from Source (Requires Go 1.26.1 or newer)
git clone https://github.com/infraspecdev/goperf.git
cd goperf
make build
./bin/goperf --helpgoperf runs the provided number of requests at the provided concurrency level and prints latency stats.
Usage: goperf run <url> [options...]
Options:
-n Number of requests to execute. Default is 1.
-c Number of concurrent workers. Default is 1.
-d Duration to run the test. When duration is reached, the application
stops and exits. If duration is specified, -n is ignored.
Examples: -d 10s, -d 1m.
-o Output format. "text" or "json". Default is text.
-m HTTP method, one of GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD.
Default is GET.
-H Custom HTTP header. You can specify as many as needed by repeating the flag.
For example: -H "Accept: text/html" -H "Content-Type: application/json".
-b HTTP request body content.
-D Path to a file containing the request body. Use this for large
payloads instead of -b.
-t Timeout for each request. Default is 10s.
-f Path to configuration file (JSON/YAML).
-v Enable verbose output. Prints every request's latency or error.
Make 100 requests sequentially:
goperf run https://httpbin.org/get -n 100Make 1000 requests with 50 concurrent workers:
goperf run https://httpbin.org/get -n 1000 -c 50Run load test for 30 seconds:
goperf run https://httpbin.org/get -c 50 -d 30sMake POST request with custom body:
goperf run https://httpbin.org/post \
-m POST \
-b '{"title":"foo","body":"bar"}'Make POST request with a body from a file:
goperf run https://httpbin.org/post \
-m POST \
-D payload.jsonExample payload.json:
{
"title": "foo",
"body": "bar",
"userId": 1
}Add custom headers:
goperf run https://httpbin.org/get \
-H "Accept: application/json" \
-H "Authorization: Bearer token"Run test using a configuration file:
goperf run -f load-test.yamlExample load-test.yaml:
target: "https://httpbin.org/post"
concurrency: 100
duration: "1m"
method: "POST"
headers:
- "Authorization: Bearer your-token-here"
- "Content-Type: application/json"
body: '{"test":"data"}'Prevent hanging requests by enforcing a strict per-request timeout:
goperf run https://httpbin.org/delay/3 -t 2sUse Verbose Mode for Debugging, print the result and latency of every individual request:
goperf run https://httpbin.org/get -n 10 -vOutput stats as JSON for CI/CD automation:
goperf run https://httpbin.org/get -n 500 -c 20 -o json-
We measure TTFB (Time To First Byte): Our timer stops the exact millisecond your server starts sending response headers. We don't include the time it takes to download the actual response body.Because we want to measure how fast your server processes data, not how fast your local internet connection is.
-
Closed-Loop Testing:
goperfsends a request, waits for the response, and then sends the next one. If you use-c 50, you will have exactly 50 connections open at all times. -
The "Coordinated Omission" : Because our workers wait for responses, if your server completely locks up for 5 seconds,
goperfwill patiently wait and stop sending new requests. This means your p99 latencies might look slightly better than reality during an outage. If you need to test traffic that hits your server at a constant, unforgiving rate (open-loop testing), we highly recommend checking out Vegeta.
$ goperf run https://httpbin.org/get -c 50 -d 7s -t 1s
Running for 7s against https://httpbin.org/get with concurrency 50
[2s] 170 reqs | 85.0/s | 45 errors <- Live progress every 2s: total requests, rate, and error count
[4s] 565 reqs | 141.2/s | 46 errors
[6s] 933 reqs | 155.5/s | 46 errors
Target: https://httpbin.org/get <- The URL that was tested
Duration: 7.001s <- Total wall-clock time of the test
Requests: 1132 total (1086 succeeded, 46 failed) <- Summary of all requests sent
Status code distribution: <- Breakdown of HTTP status codes received
[200] 1086 responses
Error distribution: <- Breakdown of network-level errors (timeouts, connection refused, etc.)
[46] context deadline exceeded <- 46 requests exceeded the 1s timeout
Latency:
Fastest: 208.76ms <- The quickest single request
Slowest: 954.37ms <- The worst outlier request
Average: 271.02ms <- Arithmetic mean of all successful requests
p50: 212.21ms <- 50% of requests were faster than this (Median)
p90: 431.23ms <- 90% of requests were faster than this
p99: 795.87ms <- 99% of requests were faster than this
Response time histogram: <- Visual distribution of response times
208.760 [826] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
283.320 [52] |■■
357.881 [131] |■■■■■■
432.442 [26] |■
507.003 [11] |
581.563 [16] |
656.124 [7] |
730.685 [6] |
805.246 [5] |
879.807 [6] |
Throughput: 161.7 requests/sec <- Overall requests completed per second
This project is licensed under the MIT License - see the LICENSE for details.
