
Load test your APIs and get hardware sizing recommendations — no scripts required.
Features •
Quick Start •
Installation •
Usage •
Architecture •
API •
Contributing
Vegeta Sizer is an open-source Go web application that imports your API documentation, runs load tests using Vegeta, visualizes performance results in real time, and estimates infrastructure sizing using heuristic linear scaling.
Ship as a single binary. No database. No configuration files. Just run it.
- API Import — OpenAPI/Swagger, Postman Collection, OpenCollection, manual entry, or paste cURL commands
- Request Organization — tree-based folder structure with drag-and-drop, duplication, and variable inheritance
- Variable Interpolation — define variables at any scope (folder or request) with
{{variable}}syntax and parent-child inheritance - Load Testing — constant RPS and step ramp attack patterns powered by Vegeta
- Live Dashboard — real-time charts for throughput, latency percentiles (P50/P90/P95/P99), error rate, CPU, and memory via WebSocket
- Saturation Detection — automatically identifies when your service hits its capacity limit
- Hardware Prediction — estimates CPU and RAM requirements for target RPS using linear scaling with a 30% safety margin
- CLI Export — generates ready-to-run
vegetaCLI commands from your configured requests - Single Binary — frontend embedded via
go:embed, ships as one executable
# Clone and build
git clone https://github.com/krismp/vegeta-sizer.git
cd vegeta-sizer
cd web/ui && npm install && npm run build && cd ../..
go build -o sizer ./cmd/sizer
# Run
./sizerOpen http://localhost:7777 in your browser.
- Go 1.24+
- Node.js 20+ (for building the frontend)
- Target API service running and reachable from the host
git clone https://github.com/krismp/vegeta-sizer.git
cd vegeta-sizer
# Build the frontend
cd web/ui
npm install
npm run build
cd ../..
# Build the binary
go build -o sizer ./cmd/sizer
# Run
./sizer# Build the image
docker build -t vegeta-sizer .
# Run (host network required to reach local services)
docker run --rm -it --network host vegeta-sizer
# With persistent data
docker run --rm -it \
--network host \
-v $(pwd)/data:/app/data \
vegeta-sizerNote:
--network hostis required so Vegeta Sizer can reach services running onlocalhost. On macOS/Windows, usehost.docker.internalas the target base URL instead.
./sizer [flags]
Flags:
--port int HTTP server port (default 7777)
--data string Data directory path (default "./data")
--dev Development mode (enables CORS, proxies frontend to Vite dev server)
Upload an OpenAPI spec, Postman Collection, or OpenCollection file. Or add endpoints manually — one at a time through a form, or bulk paste cURL commands.
Organize endpoints into folders with drag-and-drop. Define variables at the folder or request level using {{variable}} syntax — child nodes inherit parent variables, and can override them.
Vegeta Sizer collects resource usage from your target service during load tests via a Prometheus-compatible metrics endpoint. You must configure this before running a test.
| Setting | Required | Description |
|---|---|---|
| Metrics URL | Yes | Full URL to the target's /metrics endpoint (e.g., http://localhost:9090/metrics) |
| CPU Cores | No | Number of CPU cores on the target host (used for sizing predictions) |
| RAM (GB) | No | Total RAM on the target host (used for sizing predictions) |
Your target service must expose the following Prometheus metric:
| Metric | Type | Purpose |
|---|---|---|
process_cpu_seconds_total |
counter | CPU usage calculation — (delta_cpu / delta_time) * 100 |
These are collected automatically if available:
| Metric | Type | Purpose |
|---|---|---|
process_resident_memory_bytes |
gauge | Memory usage (converted to MB) |
process_network_receive_bytes_total |
counter | Network ingress (delta, MB) |
process_network_transmit_bytes_total |
counter | Network egress (delta, MB) |
process_open_fds |
gauge | Open file descriptor count |
Tip: Most Go services expose these out of the box with the Prometheus client library. For other languages, add the equivalent process metrics exporter.
Vegeta Sizer validates the metrics endpoint before starting a test — it checks that the URL is reachable and that process_cpu_seconds_total is present.
| Attack Type | Description |
|---|---|
| Constant RPS | Steady request rate for baseline measurement |
| Step Ramp | Gradually increasing RPS to find the saturation point |
| Parameter | Default | Description |
|---|---|---|
| Concurrent Users | 10 | Number of parallel workers sending requests |
| RPS per User | 10 | Request rate per worker (total RPS = users × rate) |
| Duration | 30s | How long to sustain the load |
| Max Workers | 100 | Upper bound on concurrent connections |
Total RPS is computed as Concurrent Users × RPS per User. For example, 10 users at 10 RPS/user = 100 total RPS for 30 seconds (3,000 total requests).
| Parameter | Default | Description |
|---|---|---|
| Start RPS | 10 | Request rate for the first step |
| End RPS | 200 | Request rate for the final step |
| Steps | 5 | Number of step increments (minimum 2) |
| Step Duration | 10s | Duration of each step |
| Max Workers | 100 | Upper bound on concurrent connections |
Total duration is Steps × Step Duration. For example, 5 steps at 10s each = 50 seconds total, ramping from 10 to 200 RPS in equal increments (10 → 57 → 105 → 152 → 200).
You can optionally set production targets that inform the sizing recommendations:
| Setting | Description |
|---|---|
| SLA Latency P95 | Target P95 latency threshold (ms) for your production SLA |
| Peak Traffic Goal | Target RPS your production deployment must handle |
| Redundancy | Enable N+1 redundancy in sizing calculations |
You can run a load test from a single request or from a folder. The behavior differs depending on which you choose:
Run the test from any individual request. The runner sends that single request definition repeatedly at the configured rate. Use this when you want to isolate and benchmark a specific endpoint.
Run the test from a folder node. The runner collects all requests inside that folder (including nested sub-folders) and sends them in a round-robin pattern during the test. This lets you simulate realistic mixed traffic across multiple endpoints in a single run.
Folder mode also applies folder-level headers as defaults to every child request — individual requests can still override specific headers. Configuration (base URL, attack settings, metrics URL, variables) is inherited from the folder and can be overridden at any level.
| Aspect | Request Mode | Folder Mode |
|---|---|---|
| Endpoints tested | 1 | All descendant requests (recursive) |
| Traffic pattern | Same request repeated | Round-robin across all collected endpoints |
| Headers | Request's own headers only | Folder headers merged as base + per-request overrides |
| Config inheritance | Walks ancestor chain | Same — walks ancestor chain |
| Results breakdown | Single endpoint stats | Per-endpoint breakdown for each request |
During the test, the system collects:
- Vegeta metrics — RPS, latency percentiles, error rate, throughput
- Host metrics — CPU and memory usage scraped from the target's Prometheus endpoint
Saturation is detected automatically when latency increases >2x between steps, error rate exceeds 2%, or CPU usage exceeds 90%.
After the test completes, Vegeta Sizer analyzes the results and generates hardware recommendations:
Tested: 800 RPS @ 80% CPU, 2GB RAM
Derived:
RPS per CPU = 1000
Memory per RPS = 2.5 MB
Recommendations (with 30% safety margin):
Small — 2 CPU / 4 GB → ~600 RPS
Medium — 4 CPU / 8 GB → ~1200 RPS
Large — 8 CPU / 16 GB → ~2400 RPS
You can also input a custom target RPS to get a specific CPU/RAM recommendation.
The CLI tab generates ready-to-run vegeta commands using the targets file format, so you can reproduce tests outside the UI or integrate them into CI/CD pipelines.
┌─────────────────────────────────────────────────┐
│ ./sizer binary │
│ │
│ ┌─────────────┐ ┌────────────────────────┐ │
│ │ Svelte SPA │◄──►│ Go Backend (Chi) │ │
│ │ (embedded) │ WS │ │ │
│ │ Tailwind │ │ REST API │ │
│ │ ECharts │ │ WebSocket │ │
│ └─────────────┘ │ Vegeta Engine │ │
│ │ Metrics Collector │ │
│ │ Hardware Predictor │ │
│ └────────────────────────┘ │
└─────────────────────────────────────────────────┘
│
▼
Target API Service
The application ships as a single Go binary with the frontend embedded via go:embed. All data is stored as JSON files in a local data/ directory — no database required.
| Layer | Technology |
|---|---|
| Backend | Go 1.24, Chi v5, Gorilla WebSocket |
| Frontend | Svelte 5, Vite, Tailwind CSS 4, ECharts |
| Testing | Vegeta v12 |
| Deploy | Single binary or Docker (Alpine) |
vegeta-sizer/
├── cmd/sizer/ # CLI entrypoint
├── internal/
│ ├── server/ # HTTP server, router, WebSocket hub
│ └── api/ # REST API handlers
├── pkg/
│ ├── specparser/ # OpenAPI, Postman, OpenCollection, cURL parsers
│ ├── node/ # Request/folder tree model with variables
│ ├── scenario/ # Scenario model and validation
│ ├── attack/ # Vegeta Pacer implementations
│ ├── runner/ # Load test orchestration
│ ├── metrics/ # Vegeta + host metrics collection
│ ├── analyzer/ # Performance analysis, saturation detection
│ ├── predictor/ # Hardware sizing prediction
│ ├── cligen/ # Vegeta CLI command generation
│ └── storage/ # JSON file storage
├── web/ui/ # Svelte + Vite + Tailwind frontend
├── data/ # Runtime data (gitignored)
├── Dockerfile
└── go.mod
| Method | Path | Description |
|---|---|---|
POST |
/api/spec/import |
Import API spec file |
GET |
/api/spec/ |
List imported specs |
GET |
/api/spec/{id} |
Get spec details |
GET |
/api/spec/{id}/endpoints |
List parsed endpoints |
POST |
/api/node/ |
Create request or folder |
GET |
/api/node/tree |
Get full request tree |
GET |
/api/node/{id} |
Get node details |
PUT |
/api/node/{id} |
Update node |
DELETE |
/api/node/{id} |
Delete node |
POST |
/api/node/{id}/duplicate |
Duplicate request |
PUT |
/api/node/{id}/move |
Move node to parent |
GET |
/api/node/{id}/resolve |
Resolve variables |
GET |
/api/node/{id}/cli-command |
Generate vegeta CLI command |
POST |
/api/run/ |
Start load test |
GET |
/api/run/ |
List test runs |
GET |
/api/run/{id}/metrics |
Get run metrics |
GET |
/api/run/{id}/result |
Get analysis results |
DELETE |
/api/data/runs/{id} |
Delete a test run |
DELETE |
/api/data/specs/{id} |
Delete an imported spec |
WS |
/ws/metrics |
Live metrics stream |
GET |
/api/health |
Health check |
Run the backend and frontend separately for hot reload:
# Terminal 1 — backend
go run ./cmd/sizer --dev
# Terminal 2 — frontend
cd web/ui
npm install
npm run devThe frontend dev server runs on http://localhost:5173 and proxies API requests to the Go backend on port 7777.
go test ./...Vegeta Sizer must run on the same machine (or in the same network namespace) as the target service to collect accurate host metrics via /proc. When running in Docker, use --network host.
For containerized target services, the metrics collector reads cgroup stats automatically.
- OpenAPI, Postman, OpenCollection import
- Manual endpoint entry + cURL paste
- Constant RPS and Step Ramp attacks
- Live dashboard with WebSocket streaming
- Saturation detection
- Hardware sizing predictions
- Request organization with folders and drag-and-drop
- Variable interpolation with scoped inheritance
- Vegeta CLI command export
- Spike, Soak, Burst attack patterns
- HTML/JSON/CSV report exports
- Distributed load testing
- Kubernetes metrics integration
- Cloud cost estimation
Contributions are welcome! Please open an issue to discuss your idea before submitting a pull request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/my-feature) - Commit your changes (
git commit -m 'Add my feature') - Push to the branch (
git push origin feature/my-feature) - Open a Pull Request
This project is licensed under the MIT License — see the LICENSE file for details.

