vegeta 12.13.0 is an HTTP load testing tool driven entirely from the command line: attack at a fixed rate for a fixed duration, save the results to a file, then analyse that file separately.

The problem it solves is repeatable measurement. A single run tells you what happened once; a saved result file lets you recompute the same numbers later, compare two builds, or plot the latency series without re-running the test.

I ran three fixed rates against a local single-threaded server serving a 130780-byte file, then read each result file back with report.

One 11425280-byte exe

Single file, no installer, no runtime. Written in Go, so the whole image is self-contained.

ItemValueNote
Release zip4463961 bytesvegeta_12.13.0_windows_amd64.zip
vegeta.exe11425280 bytesStandalone
Target130780 bytesA local static file over http.server
Duration per run3 sFixed for all three rates

Attack and report are separate commands

attack writes binary results to a file, report turns that file into numbers. This split is the whole design: the test does not decide which metrics matter, the analysis step does.

The rate is the input, not the concurrency

There is no connections flag in these runs. You state requests per second and a duration, and the tool works out how many virtual users it needs. That makes the load profile explicit rather than emergent.

Three rates, three result files

Each run asked for a constant rate for three seconds. The achieved rate matched the asked-for rate in all three.

RequestedCompletedAchieved rateSuccess
50/s15050.34100.00%
200/s600200.41100.00%
500/s1500500.17100.00%

150 requests in three seconds at 50/s

50 times 3 equals 150, and that is exactly what completed. There is no warm-up phase and no ramp, so the arithmetic is visible in the output.

All three runs succeeded

Success 100.00% at every level, including 500 per second. The server was a plain single-threaded http.server, so this is more a statement about a 130 KB static file than about the tool.

Latency went down as the rate went up

This is the result I did not expect. The 50/s run has a median of 2.88 ms; the 500/s run has a median of 0.976 ms.

Ratemeanp50p90p99max
50/s4.805 ms2.88 ms4.76 ms81.361 ms82.896 ms
200/s1.988 ms1.251 ms2.909 ms15.031 ms20.042 ms
500/s1.443 ms0.976 ms2.032 ms9.492 ms15.049 ms

The 50/s run has a 81 ms tail

At 50 per second each request arrives 20 ms apart, so the server is idle between them. A median of 2.88 ms with a 99th percentile of 81.361 ms means a handful of requests waited about 80 ms while the rest were fast.

The 500/s run spreads the work evenly

At 500 per second requests arrive every 2 ms and the server never idles. The spread between p50 and p99 shrinks to 8.5 ms, because there is no idle period for a request to land in the wrong state.

The result file reached 196 MB

By default vegeta stores the full response body with each result. Three seconds at 500 per second serving 130780 bytes is 196 MB of result file.

RateResult fileBytes In
50/s1965578019617000
200/s7862324478468000
500/s196558336196170000

Result file is slightly bigger than the payload

196558336 against 196170000 is a 388336-byte difference across 1500 requests, about 259 bytes of metadata per request. Everything else is the response body itself.

This is why long tests need a body limit

A ten-minute run at 500 per second against the same target would write roughly 39 GB. Against a real API returning 2 MB responses, three seconds would be over 3 GB. The body has to be discarded or truncated for anything longer than a smoke test.

What report gives you from the file

Every number above comes from reading a saved file, not from the run itself. The same file can be re-read with different options, or exported and plotted.

FieldMeaning
Requeststotal, achieved rate, throughput
Durationtotal, attack, and wait after the last request
Latenciesmin, mean, 50, 90, 95, 99, max
Bytes In / Outtotal and mean per request
Successratio of non-error responses
Status Codescount per HTTP status

Duration separates attack from wait

The 200/s run reports 2.995 s total, 2.994 s attack and 949.9 µs wait. The wait is the time spent collecting the last in-flight responses after the timer stopped, which is a useful check that the run did not leave requests hanging.

vegeta 12.13.0 report output in a Windows console for two runs: the 500 req/s run shows 1500 requests at 500.17 with latencies min 509.7us mean 1.443ms p50 976.361us p99 9.492ms max 15.049ms and 196170000 bytes in, the 200 req/s run shows 600 requests at 200.41 with p50 1.251ms and p99 15.031ms

Mean is misleading here

At 50/s the mean is 4.805 ms against a median of 2.88 ms. The gap is the 81 ms tail pulling the average up. Reading only the mean would suggest the 50/s run was slower per request than the 500/s run, which the percentiles contradict.

Targets come from a file, one definition per line

The whole test input for these runs was a single line: GET http://127.0.0.1:18090/doc_1000.md. Fifteen characters of method, one space, then the URL. Anything more complex — headers, a request body, a POST — is expressed by adding lines to that same file rather than by flags on the command.

One file can hold several endpoints

Because targets live in a file, a run can round-robin across several URLs by adding more lines. That keeps the load profile in version control next to the code, and means the exact request mix can be reproduced from the file alone.

Where it earns a place

Fixed-rate load against an endpoint you control, where you want the raw results kept so the same numbers can be recomputed later.

TaskFitWhy
Rate-limited load testHighRate is the input, achieved rate is reported
Comparing two buildsHighSaved files can be re-reported side by side
Long soak runsLowResult file grows with the response body
Ad-hoc "is it up" checkLowTwo commands, and a file to keep track of

It does not pick the target for you

Targets come from a file, one line per request definition. There is no built-in scenario language, so multi-step flows such as login then fetch need to be expressed as separate target files or driven from outside.

Licence and cost

MIT. Free for personal and commercial use, source on GitHub, written in Go. The Windows build is one exe with no installer and no registry writes.