RepoPilotOpen in app →

tsenart/vegeta

HTTP load testing tool and library. It's over 9000!

Healthy

Healthy across the board

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 3mo ago
  • 32+ active contributors
  • MIT licensed
Show 3 more →
  • CI configured
  • Tests present
  • Concentrated ownership — top contributor handles 50% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/tsenart/vegeta)](https://repopilot.app/r/tsenart/vegeta)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/tsenart/vegeta on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: tsenart/vegeta

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/tsenart/vegeta shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 3mo ago
  • 32+ active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Concentrated ownership — top contributor handles 50% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live tsenart/vegeta repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/tsenart/vegeta.

What it runs against: a local clone of tsenart/vegeta — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in tsenart/vegeta | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 112 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>tsenart/vegeta</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of tsenart/vegeta. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/tsenart/vegeta.git
#   cd vegeta
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of tsenart/vegeta and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "tsenart/vegeta(\\.git)?\\b" \\
  && ok "origin remote is tsenart/vegeta" \\
  || miss "origin remote is not tsenart/vegeta (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "lib/attack.go" \\
  && ok "lib/attack.go" \\
  || miss "missing critical file: lib/attack.go"
test -f "lib/targets.go" \\
  && ok "lib/targets.go" \\
  || miss "missing critical file: lib/targets.go"
test -f "lib/metrics.go" \\
  && ok "lib/metrics.go" \\
  || miss "missing critical file: lib/metrics.go"
test -f "lib/pacer.go" \\
  && ok "lib/pacer.go" \\
  || miss "missing critical file: lib/pacer.go"
test -f "lib/reporters.go" \\
  && ok "lib/reporters.go" \\
  || miss "missing critical file: lib/reporters.go"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 112 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~82d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/tsenart/vegeta"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Vegeta is a high-performance HTTP load testing tool and library written in Go that generates constant-rate traffic to drill HTTP services. It's designed to avoid Coordinated Omission—a common pitfall where load generators underreport latency—and provides extensive reporting with histogram metrics, plot generation, and support for distributed testing across multiple machines. Single-package design where the CLI wraps the library: root-level files like attack.go, dump.go, encode.go contain CLI command implementations; lib/ directory (lib/attack.go, lib/metrics.go, lib/pacer.go, lib/histogram.go) provides the core load-testing library; internal/cmd/ houses utility servers (echosrv for testing, jsonschema for schema generation); lib/plot/ contains embedded HTML templating and JavaScript assets for report generation.

👥Who it's for

DevOps engineers and performance testers who need to benchmark HTTP services under sustained load; backend developers who want to stress-test APIs with precise rate control; organizations running Kubernetes clusters that need reproducible, distributed load testing without complex setup.

🌱Maturity & risk

Production-ready and actively maintained. The project has reached v12 for the library (following semantic versioning split from v8 onwards), includes comprehensive CI/CD via GitHub Actions (.github/workflows/ci.yml), extensive test coverage (attack_test.go, lib/histogram_test.go, lib/pacer_test.go), and a mature feature set supporting Prometheus metrics, DNS caching, and plot generation. Single maintainer (tsenart) but stable release cadence and well-documented contribution process.

Low risk for core functionality, moderate dependency footprint (~18 direct dependencies in go.mod including prometheus/client_golang and influxdata/tdigest). Minor risk: single maintainer model and Go 1.22 minimum requirement could limit contribution velocity. Library and CLI are now versioned separately (cli/vX.Y.Z and lib/vX.Y.Z tags), which reduces breaking change impact but requires awareness when upgrading.

Active areas of work

Recent focus includes Go 1.22 support (visible in go.mod), Prometheus metrics integration (prometheus/client_golang in dependencies), LTTB downsampling for plot rendering (lib/lttb/), and DNS resolution caching (internal/resolver/). The Dependabot configuration (.github/dependabot.yml) indicates active dependency management. No visible open milestone data, but the codebase shows stabilization around performance metrics and reporting.

🚀Get running

git clone https://github.com/tsenart/vegeta
cd vegeta
make vegeta
mv vegeta ~/bin

Or via Homebrew (macOS): brew install vegeta. The Makefile orchestrates the build; running make vegeta produces a static binary ready to use.

Daily commands: CLI: vegeta attack -rate=100 -duration=30s -targets=targets.txt | vegeta report (read targets from file, sustain 100 req/s for 30s, print summary). Library: Import github.com/tsenart/vegeta/v12/lib and use lib.NewAttacker() with lib.Attack() to programmatically run load tests. See Makefile for dev targets: make test runs unit tests, make build creates CLI binary.

🗺️Map of the codebase

  • lib/attack.go — Core attack execution engine—implements the Attacker type and request dispatching loop that drives all load testing campaigns
  • lib/targets.go — Target parsing and validation—defines the Target struct and codec for reading attack targets from various formats (CSV, JSON)
  • lib/metrics.go — Results aggregation and metric computation—calculates latency percentiles, throughput, and all reported statistics
  • lib/pacer.go — Request rate scheduling—implements pacing strategies (constant, linear, exponential) to control load shape
  • lib/reporters.go — Output formatters for text, JSON, and specialized reporters—defines the report generation interface used by CLI
  • main.go — CLI entry point and subcommand router—orchestrates attack, report, dump, encode, and plot workflows
  • attack.go — Platform-specific attack wrappers—handles OS-level concurrency and file descriptor limits for Windows and UNIX

🛠️How to make changes

Add a new output report format

  1. Define a new reporter struct implementing the Reporter interface in lib/reporters.go (lib/reporters.go)
  2. Register the reporter in the format map and wire it into the report CLI subcommand (report.go)
  3. Add format flag parsing and output handling (follow text/JSON reporter patterns) (flags.go)
  4. Write tests for your reporter using the existing reporter test patterns (lib/reporters_test.go)

Add a new pacing strategy

  1. Implement the Pacer interface in lib/pacer.go with your rate schedule logic (lib/pacer.go)
  2. Add a constructor function and register it in the pacing strategy factory (lib/pacer.go)
  3. Wire the new pacing strategy into the CLI attack subcommand flag parsing (attack.go)
  4. Add benchmark and unit tests following lib/pacer_test.go patterns (lib/pacer_test.go)

Add a new metric to results and reports

  1. Add the metric field to the Result struct in lib/results.go (lib/results.go)
  2. Regenerate easyjson codecs by running go generate ./lib to update results_easyjson.go (lib/results_easyjson.go)
  3. Add aggregation logic in lib/metrics.go to compute the metric from individual results (lib/metrics.go)
  4. Update the text and JSON reporters in lib/reporters.go to display the new metric (lib/reporters.go)
  5. Add Prometheus metric exposition in lib/prom/prom.go if applicable (lib/prom/prom.go)

Add support for a new target format

  1. Define a new codec type implementing the Codec interface in lib/targets.go (lib/targets.go)
  2. Implement Decode() and Encode() methods to marshal/unmarshal your format (lib/targets.go)
  3. Register the codec in the format map in lib/targets.go (lib/targets.go)
  4. Add round-trip tests in lib/targets_test.go (lib/targets_test.go)

🔧Why these technologies

  • Go (1.22+) — Lightweight goroutines enable thousands of concurrent requests; fast compilation and single binary distribution; strong standard library for HTTP and networking
  • T-Digest histogram (influxdata/tdigest) — Accurate percentile calculation under streaming conditions without storing all raw latencies; critical for memory efficiency under high-volume attacks
  • easyjson codegen — Zero-allocation JSON serialization for results stream; avoids GC pressure during sustained load testing
  • DNS caching (rs/dnscache) — Eliminates DNS lookup latency per request; attacks must measure server latency, not resolver latency
  • uPlot charting library — Lightweight client-side rendering for large time-series datasets; interactive plots without server-side rendering overhead
  • Prometheus client_golang — Native metrics export for integration with Prometheus monitoring; enables long-term load test data collection

⚖️Trade-offs already made

  • Single-threaded per goroutine request dispatch (no thread pooling)

    • Why: Go's goroutines are lightweight enough for thousands of concurrent requests; avoids OS context-switching overhead
    • Consequence: Maximum throughput scales with goroutine count and GC pauses; not suitable for >1M requests/sec on a single machine
  • Streaming results (no in-memory accumulation)

    • Why: Allows reporting on long-running attacks without memory explosion; fits UNIX pipe philosophy
    • Consequence: Cannot retroactively change output format after attack completes; must decide reporter at runtime
  • T-Digest histogram instead of raw samples

    • Why: Bounded memory footprint regardless of result count; constant-time percentile queries
    • Consequence: Percentile accuracy degrades at extreme tails (p99.99); not suitable for precise SLA verification at 5-9s
  • CLI-first design with library API as secondary

    • Why: Composability with shell pipelines; each subcommand is independent and chainable
    • Consequence: Library API is thin wrapper around CLI logic; less idiomatic Go library than CLI tool

🚫Non-goals (don't propose these)

  • Real-time attack adjustment based on live metrics (non-interactive tool)
  • Support for HTTPS mutual TLS or certificate pinning (delegates to Go stdlib)
  • Distributed load testing across multiple machines (single-process tool)
  • WebSocket or gRPC load testing (HTTP/1.1–2.0 only)
  • Server-side metrics collection or agent deployment
  • GUI or web dashboard (CLI + static HTML plots only)

🪤Traps & gotchas

  1. Coordinated Omission: Vegeta deliberately pre-computes request timings (lib/pacer.go) to avoid the classic load-tester pitfall; understand token bucket behavior before tuning rate/workers. 2. Platform differences: attack_windows.go vs attack_nonwindows.go handle OS-specific file/socket behavior; Windows may have different TCP stack limits. 3. DNS caching: internal/resolver/ caches DNS results; TTL handling may cause stale IPs in long-running tests against dynamic hosts. 4. Memory with high volumes: histogram.go uses tdigest which is memory-efficient but still scales with request count; very high -rate tests (millions/sec) require tuning workers and memory. 5. Go 1.22 minimum: no older Go versions supported; some CI systems may not have this available.

🏗️Architecture

💡Concepts to learn

  • Coordinated Omission — Vegeta was explicitly designed to avoid this pitfall where load generators hide latency by skipping requests when the system is slow; understanding this is critical to interpreting results correctly
  • Token Bucket Rate Limiter — Vegeta's pacer.go implements token bucket to maintain constant request rate; understanding refill logic and worker coordination is essential for tuning load tests
  • Percentile Latency Histograms (T-Digest) — Vegeta uses influxdata/tdigest to compute accurate p50/p95/p99 latencies across millions of requests without storing all samples; critical for performance reporting
  • DNS Caching and TTL Handling — internal/resolver uses rs/dnscache to avoid DNS lookup overhead during sustained tests; matters for long-running tests and discovering stale upstream IPs
  • LTTB (Largest-Triangle-Three-Buckets) Downsampling — lib/lttb reduces thousands of data points to ~200 for plot rendering while preserving visual fidelity; enables interactive HTML reports without overwhelming browsers
  • Constant-Rate vs Constant-Concurrency Load Models — Vegeta targets constant request rate (e.g., 1000 req/s) rather than fixed worker count; this is the defining difference vs tools like Apache Bench and requires understanding of token bucket and adaptive concurrency
  • Go Embedding and Template Asset Pipeline — lib/plot/ uses Go's embed package to bundle HTML/JS assets and go templates to render interactive plots; important for understanding report generation and customizing output
  • grafana/k6 — Modern JavaScript-based load testing with similar CLI composability and distributed testing; Go-written competitor with more advanced scripting capabilities
  • grpc-ecosystem/ghz — gRPC load testing tool using similar patterns (rate limiting, metrics aggregation); complements Vegeta for non-HTTP protocols
  • tsenart/unitbench — By same author; provides microbenchmarking patterns that pair with Vegeta's macro-level load testing
  • prometheus/client_golang — Direct dependency (github.com/prometheus/client_golang in go.mod); Vegeta exports metrics via this library for Prometheus ingestion
  • kubernetes/kubernetes — Vegeta's distributed load testing patterns are designed for Kubernetes; README links to Kubernetes blog post on 1M req/s testing with Vegeta

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive integration tests for the CLI attack command with Windows support

The repo has platform-specific implementations (attack_windows.go, attack_nonwindows.go) but attack_test.go likely lacks Windows-specific test coverage. Given that vegeta is a load testing tool used across platforms, ensuring parity between Windows and Unix implementations is critical. New contributors can add integration tests that verify attack behavior on Windows, including file handle limits and connection handling.

  • [ ] Review existing attack_test.go to identify gaps in Windows-specific scenarios
  • [ ] Add test cases in attack_test.go that validate Windows connection handling (e.g., IOCP, socket limits)
  • [ ] Create platform-specific test files (attack_windows_test.go) for Windows-only edge cases
  • [ ] Verify tests pass on Windows CI (may require updating .github/workflows/ci.yml)

Add DNS resolution caching tests and benchmarks for the internal/resolver package

The repo includes internal/resolver/resolver.go and uses github.com/rs/dnscache as a dependency, but resolver_test.go appears minimal. DNS caching is critical for load testing accuracy and performance. New contributors can expand test coverage to validate caching behavior, TTL handling, and concurrent resolution patterns that are essential for high-throughput scenarios.

  • [ ] Review internal/resolver/resolver_test.go and identify missing test scenarios
  • [ ] Add tests for DNS cache hits/misses, TTL expiration, and concurrent resolver access
  • [ ] Add benchmarks (e.g., TestBenchmarkResolver) to measure cache performance vs. uncached resolution
  • [ ] Document resolver behavior in a comment block explaining caching guarantees

Add end-to-end tests for the plot/reporting pipeline with golden file validation

The lib/plot and lib/prom packages generate HTML reports and Prometheus metrics, with a golden test file (lib/plot/testdata/TestPlot.golden.html) present. However, there's likely no corresponding test for Prometheus output (prom_test.go) or validation that metrics output format matches expected schemas. New contributors can add golden file tests for Prometheus metric generation and validate the complete reporting pipeline with various result sets.

  • [ ] Check lib/prom/prom_test.go for coverage gaps in Prometheus metric output formatting
  • [ ] Add golden file test (lib/prom/testdata/TestPromMetrics.golden.txt) validating Prometheus exposition format
  • [ ] Create test cases that generate metrics from sample attack results and verify output structure
  • [ ] Add validation that histogram buckets and metric labels match Prometheus best practices

🌿Good first issues

  • Add unit tests for dump.go (handles response body output) which currently lacks dedicated test coverage; start by writing DumpResponse() test cases in dump_test.go for various response encodings.
  • Extend lib/metrics.go to expose additional Prometheus histogram buckets (currently implicitly defined via tdigest); expose custom bucket configuration to library users and add tests in lib/metrics_test.go.
  • Document the internal/cmd/echosrv test server's usage in README or CONTRIBUTING.md; add example in examples/ showing how to use echosrv as a target for local load testing demos.

Top contributors

Click to expand
  • @tsenart — 50 commits
  • @dependabot[bot] — 11 commits
  • [@Tomás Senart](https://github.com/Tomás Senart) — 8 commits
  • @rs — 2 commits
  • @fxkr — 2 commits

📝Recent commits

Click to expand
  • cf58112 — Replace hero image with custom cyberpunk-anime artwork (tsenart)
  • 507c4f0 — Fix sort instability in plot data ordering (tsenart)
  • 4b240c3 — Update golden test file for uPlot migration (tsenart)
  • 6cbc5ba — Migrate plot command from Dygraphs to uPlot (tsenart)
  • 03ca49e — lib,cmd: add Dan as contributor for -connect-to (tsenart)
  • 647dacc — lib,cmd: add -connect-to flag (tsenart)
  • ce93cd8 — lib: use fixed IP selection function (tsenart)
  • 1799abc — lib: fix IP selection in DNS caching (tsenart)
  • b0b14b9 — lib/prom: fix broken test after dep upgrade (tsenart)
  • fc8add3 — more dep updates (tsenart)

🔒Security observations

Vegeta codebase shows a generally solid security posture for an open-source load testing tool. No critical vulnerabilities were identified in the dependency list or configuration files. Main concerns are infrastructure-related: outdated base images (Go 1.20, Alpine 3.18), missing Docker security best practices (non-root user), and absence of modern supply chain security mechanisms. The codebase itself lacks obvious injection vulnerabilities, hardcoded secrets, or misconfigurations. Recommendations focus on updating base images, implementing least-privilege container execution, and strengthening build/release processes.

  • Medium · Outdated Go Version in Dockerfile — Dockerfile (line 1). The Dockerfile uses golang:1.20-alpine3.18 as the base image for the build stage. Go 1.20 reached end-of-life in August 2023. The go.mod specifies Go 1.22, creating a version mismatch. Using outdated versions may expose the build to known vulnerabilities. Fix: Update the Dockerfile to use golang:1.22-alpine3.18 or later to match the go.mod requirement and ensure latest security patches are applied.
  • Medium · Outdated Alpine Base Image — Dockerfile (line 13). The runtime stage uses alpine:3.18.0, which is pinned to a specific patch version. Alpine 3.18 has reached end-of-life. This may lack critical security updates for system-level dependencies. Fix: Update to alpine:3.20 (latest stable) or at minimum alpine:3.19 to ensure access to current security patches.
  • Medium · No Multi-stage Image Optimization — Dockerfile (lines 3-4). While the Dockerfile uses multi-stage builds, the build stage pulls unnecessary dependencies (make, build-base, git) that are not cleaned up and could increase attack surface if accidentally included in intermediate layers. Fix: Ensure build tools are only in the builder stage and verify they are not inadvertently included in the final image. Consider using --platform flags for reproducible builds.
  • Low · Missing HEALTHCHECK in Docker — Dockerfile. The Dockerfile does not include a HEALTHCHECK directive. For a load testing tool deployed as a service, health checks are important for orchestration systems. Fix: Add a HEALTHCHECK instruction (if applicable for your use case) or document why it's not needed for this tool's typical deployment.
  • Low · No User Privilege Restriction — Dockerfile (line 15). The Dockerfile does not specify a non-root USER directive. The binary runs as root by default, which violates the principle of least privilege. Fix: Add a non-root user and switch to it before the ENTRYPOINT: RUN addgroup -g 1000 vegeta && adduser -D -u 1000 -G vegeta vegeta && USER vegeta
  • Low · Dependency License and Source Verification — go.mod and go.sum. The go.mod includes dependencies from various sources (github.com, golang.org, pgregory.net) without explicit vendoring visible in the structure. While not a direct vulnerability, lack of vendor directory may complicate supply chain security audits. Fix: Consider running go mod vendor to create a vendor directory and commit go.sum for verified reproducible builds. Ensure go.sum is properly validated.
  • Low · No Code Signing or Build Attestation — .github/workflows/ci.yml (not shown in detail). The Makefile and CI pipeline (from file structure) don't show explicit code signing or build artifact attestation mechanisms, making it difficult to verify binary integrity. Fix: Implement code signing for releases and consider using tools like cosign for container image attestation and SLSA provenance tracking.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · tsenart/vegeta — RepoPilot