Overview
Vegeta is an open-source HTTP load testing tool and library written in Go. It provides a simple command-line interface for generating constant request rates against HTTP services and producing detailed latency histograms, percentile reports, and real-time metrics. Vegeta’s Unix philosophy design makes it composable with other tools via pipes.
Unlike many load testing tools that simulate concurrent users, Vegeta focuses on maintaining a constant request rate, which provides more predictable and reproducible results. It supports HTTP/1.1 and HTTP/2, custom headers, request bodies, and multiple output formats including JSON, CSV, and HDR histogram plots.
Installation
# macOS via Homebrew
brew install vegeta
# Go install
go install github.com/tsenart/vegeta/v12@latest
# Download prebuilt binary (Linux amd64)
curl -L https://github.com/tsenart/vegeta/releases/download/v12.12.0/vegeta_12.12.0_linux_amd64.tar.gz | tar xz
sudo mv vegeta /usr/local/bin/
# Verify installation
vegeta --version
Core Commands
| Command | Description |
|---|
vegeta attack | Generate load against targets |
vegeta report | Generate reports from results |
vegeta encode | Encode results between formats |
vegeta plot | Generate HTML latency plots |
vegeta dump | Dump raw results |
Basic Usage
# Simple attack at 50 requests/sec for 30 seconds
echo "GET https://api.example.com/health" | vegeta attack -rate=50 -duration=30s | vegeta report
# Attack with output to file
echo "GET https://api.example.com/" | vegeta attack -rate=100 -duration=60s > results.bin
# Generate report from saved results
vegeta report results.bin
# Generate JSON report
vegeta report -type=json results.bin
# Generate HDR histogram
vegeta report -type=hist[0,5ms,10ms,25ms,50ms,100ms,500ms,1s] results.bin
Target Specification
# Single target
echo "GET https://api.example.com/" | vegeta attack -rate=10 -duration=10s | vegeta report
# Multiple targets from file
cat targets.txt | vegeta attack -rate=50 -duration=30s | vegeta report
# targets.txt format
# GET https://api.example.com/users
# GET https://api.example.com/products
# POST https://api.example.com/orders
# Content-Type: application/json
# @body.json
GET https://api.example.com/users
Authorization: Bearer token123
POST https://api.example.com/users
Content-Type: application/json
@create-user.json
PUT https://api.example.com/users/1
Content-Type: application/json
{"name": "Updated User"}
DELETE https://api.example.com/users/1
Attack Options
| Flag | Description |
|---|
-rate=N | Requests per second (default: 50) |
-rate=N/ms | Requests per millisecond |
-duration=Ns | Duration of the attack |
-max-workers=N | Maximum number of workers (default: 10) |
-connections=N | Max open idle connections per target |
-timeout=Ns | Request timeout |
-header="K: V" | Custom header (repeatable) |
-body=file | Request body file path |
-cert=file | TLS client certificate |
-key=file | TLS client private key |
-root-certs=file | TLS root certificates |
-http2 | Enable HTTP/2 |
-insecure | Skip TLS certificate verification |
-lazy | Read targets lazily |
-max-body=-1 | Max bytes to capture from response body (-1 = unlimited) |
-name=string | Attack name for reports |
-redirects=N | Max redirects to follow (-1 = none) |
-workers=N | Initial number of workers |
# Full example with many options
echo "POST https://api.example.com/data" | \
vegeta attack \
-rate=200 \
-duration=120s \
-timeout=5s \
-header="Authorization: Bearer mytoken" \
-header="Content-Type: application/json" \
-body=payload.json \
-max-workers=50 \
-connections=100 \
-http2 \
> results.bin
Report Types
# Text report (default)
vegeta report results.bin
# JSON report
vegeta report -type=json results.bin
# Histogram
vegeta report -type='hist[0,10ms,50ms,100ms,200ms,500ms,1s,5s]' results.bin
# HTML plot
vegeta plot results.bin > plot.html
# Combine multiple results
vegeta report results1.bin results2.bin
# CSV encoding
vegeta encode --to csv < results.bin > results.csv
Sample Text Report Output
Requests [total, rate, throughput] 15000, 50.00, 49.97
Duration [total, attack, wait] 5m0.023s, 5m0s, 23.45ms
Latencies [min, mean, 50, 90, 95, 99, max] 1.2ms, 15.3ms, 12.1ms, 28.4ms, 45.2ms, 120.5ms, 512.3ms
Bytes In [total, mean] 4500000, 300.00
Bytes Out [total, mean] 0, 0.00
Success [ratio] 99.87%
Status Codes [code:count] 200:14980 503:20
Advanced Usage
Ramp-Up Rate
# Use shell scripting to ramp up
for rate in 10 25 50 100 200; do
echo "GET https://api.example.com/" | \
vegeta attack -rate=$rate -duration=30s -name="rate-$rate" >> results.bin
done
vegeta report results.bin
vegeta plot results.bin > ramp-report.html
JSON Targets
# Use jq to generate targets dynamically
jq -r '.users[] | "GET https://api.example.com/users/\(.id)"' users.json | \
vegeta attack -rate=20 -duration=60s | vegeta report
Distributed Testing
# Machine 1
echo "GET https://api.example.com/" | vegeta attack -rate=500 -duration=60s > results1.bin
# Machine 2
echo "GET https://api.example.com/" | vegeta attack -rate=500 -duration=60s > results2.bin
# Combine results on any machine
vegeta report results1.bin results2.bin
Pipeline with Real-Time Monitoring
# Real-time reporting every 5 seconds
echo "GET https://api.example.com/" | \
vegeta attack -rate=100 -duration=300s | \
vegeta report -every=5s
Using as a Go Library
package main
import (
"fmt"
"time"
vegeta "github.com/tsenart/vegeta/v12/lib"
)
func main() {
rate := vegeta.Rate{Freq: 100, Per: time.Second}
duration := 30 * time.Second
targeter := vegeta.NewStaticTargeter(vegeta.Target{
Method: "GET",
URL: "https://api.example.com/",
})
attacker := vegeta.NewAttacker()
var metrics vegeta.Metrics
for res := range attacker.Attack(targeter, rate, duration, "Load Test") {
metrics.Add(res)
}
metrics.Close()
fmt.Printf("99th percentile: %s\n", metrics.Latencies.P99)
fmt.Printf("Success ratio: %.2f%%\n", metrics.Success*100)
}
Configuration
# Environment variables for proxy
export HTTP_PROXY=http://proxy.example.com:8080
export HTTPS_PROXY=http://proxy.example.com:8080
# TLS configuration
vegeta attack -cert=client.crt -key=client.key -root-certs=ca.crt \
-rate=50 -duration=30s < targets.txt | vegeta report
Troubleshooting
| Issue | Solution |
|---|
too many open files | Increase ulimit: ulimit -n 65535 |
| Connection refused | Check target URL and server availability |
| All requests timing out | Increase -timeout or check network connectivity |
| Inconsistent results | Ensure the test machine is not CPU/network bottlenecked |
| HTTP/2 not working | Verify server supports HTTP/2 and use -http2 flag |
| Low throughput | Increase -max-workers and -connections |
| Binary results corrupted | Ensure stdout is not mixed with stderr; redirect properly |
| Rate not achieved | Increase -workers initial count or check system resources |