blast docs
blast is a config-driven API load tester and mock server written in Rust. Define your endpoints in blast.config.json, then hit every one with a single command — no code, no scripting.
It supports fake data generation via {{fake.*}} placeholders, request chaining using JSON extraction and dot-path rules, fixed-RPS load tests, and stress ramp tests that auto-detect where your API breaks.
Installation
Linux & macOS
curl -fsSL https://raw.githubusercontent.com/Walon-Foundation/blast/main/install.sh | shDetects your OS and architecture. Downloads the pre-built binary to ~/.local/bin. See the install guide for custom install paths.
Windows (PowerShell)
irm https://raw.githubusercontent.com/Walon-Foundation/blast/main/install.ps1 | iexInstalls the x86_64-pc-windows-msvc binary and adds it to your user PATH.
Build from source
cargo install --git https://github.com/Walon-Foundation/blastRequires Rust 1.75 or later. Cross-compile targets are listed in the repository.
Quick start
# 1. Create a starter config in the current directory
blast init
# 2. Verify the config is valid and show all endpoints
blast validate
# 3. Hit every endpoint once to confirm they respond
blast check
# 4. Seed test data (runs endpoints tagged "seed")
blast seed --count 50 --concurrency 10
# 5. Fixed-rate load test (endpoints tagged "run")
blast run --rps 50 --duration 60
# 6. Stress ramp — finds the breaking point
blast stress --min-rps 10 --max-rps 200 --step 20 --step-duration 30Commands
blast init [path]
Creates blast.config.json in the given directory (default: current directory). The generated file includes example endpoints with fake data placeholders. Edit it to describe your API, then run blast check.
blast init
blast init ./my-apiblast validate
Loads and validates the config. Prints the base URL, total endpoint count, and a table of all endpoints with their method, path, and tags. Exits non-zero on any validation error — useful as a CI gate to catch broken configs early.
blast check
Hits every endpoint once in order. Merges global headers with per-endpoint headers. Extracts values from successful responses so later endpoints can use them. Prints a coloured pass/fail table with per-request timing. Exits non-zero on any failure.
blast seed
Runs all endpoints tagged "seed" N times with configurable concurrency. Each iteration is fully independent with its own extraction context. Use this to pre-populate a test database before a load test.
| Flag | Default | Description |
|---|---|---|
| --count | 10 | Total number of iterations |
| -j, --concurrency | 1 | Maximum parallel requests |
blast seed --count 1000 --concurrency 20blast run
Fixed-RPS load test. Uses a tokio interval ticker to maintain the target request rate. Round-robins over endpoints tagged "run". Prints live per-second progress. Prints a final summary with p50, p95, p99, and p999 latency percentiles.
| Flag | Default | Description |
|---|---|---|
| --rps | 10 | Target requests per second |
| -d, --duration | 30 | Test duration in seconds |
blast run --rps 100 --duration 120blast stress
RPS ramp test. Steps from --min-rps to --max-rps in increments of --step. Stops early when p99 exceeds 500ms or the error rate exceeds 1%. Prints a per-step coloured result table and a final recommendation showing the last stable RPS.
| Flag | Default | Description |
|---|---|---|
| --min-rps | 10 | Starting RPS |
| --max-rps | 100 | Maximum RPS to reach |
| --step | 10 | RPS increase per step |
| --step-duration | 15 | Seconds to hold each step |
blast stress --min-rps 10 --max-rps 500 --step 50 --step-duration 20blast mock
Starts a local HTTP server from your blast.config.json. Every endpoint becomes a live route. Frontend developers can point their app at http://localhost:<port> and build against realistic responses without waiting for the real backend.
Response bodies are read from the mock_response field on each endpoint. {{fake.*}} placeholders are resolved on every request, so each response gets fresh data. If no mock_response is defined, the route returns {"status": "ok"} with the declared status code.
| Flag | Default | Description |
|---|---|---|
| --port | 4000 | Port to listen on |
| --config | blast.config.json | Path to config (auto-detected if omitted) |
blast mock
blast mock --port 8080
blast mock --config ./api/blast.config.json$ blast mock --port 4000
Loaded blast.config.json
GET /api/v1/users 200
POST /api/v1/auth/register 201
POST /api/v1/auth/login 200
GET /api/v1/users/{id} 200
DELETE /api/v1/users/{id} 204
5 routes mounted
Listening on http://localhost:4000Configuration
blast reads blast.config.json from the current directory (or the path passed to --config). The file has a flat structure — a base URL, global headers, an optional setup array, and an endpoints array.
{
"base_url": "http://localhost:3000",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer {{token}}"
},
"setup": [
{
"name": "login",
"method": "POST",
"path": "/api/v1/auth/login",
"body": { "email": "admin@example.com", "password": "Admin1234!" },
"expect_status": 200,
"extract": { "token": "data.access_token" }
}
],
"endpoints": [
{
"name": "register user",
"method": "POST",
"path": "/api/v1/auth/register",
"body": {
"email": "{{fake.email}}",
"password": "{{fake.password}}",
"name": "{{fake.name}}"
},
"expect_status": 201,
"tags": ["seed"]
},
{
"name": "list users",
"method": "GET",
"path": "/api/v1/users",
"expect_status": 200,
"weight": 3,
"tags": ["run"]
},
{
"name": "get user",
"method": "GET",
"path": "/api/v1/users/{{user_id}}",
"expect_status": 200,
"tags": ["run"]
}
]
}Endpoint fields
| Field | Type | Description |
|---|---|---|
| name | string | Human-readable label shown in output |
| method | string | HTTP method — GET, POST, PUT, PATCH, DELETE |
| path | string | URL path, appended to base_url. Supports {{placeholders}}. |
| headers | object | Per-endpoint headers, merged with global headers |
| body | object | Request body (JSON). Supports {{fake.*}} placeholders. |
| expect_status | integer | Expected HTTP status code; counted as failure if response differs |
| extract | object | Map of variable name → dot-path to extract from response JSON |
| weight | integer | Relative traffic weight for load distribution (default: 1) |
| tags | array | Commands that pick up this endpoint: "seed", "run", "stress" |
| mock_response | object | Body returned by blast mock for this route |
Fake data
Use {{fake.*}} placeholders in request body examples or header values. A new value is generated per request — every iteration of blast seed and every request in blast run gets fresh data.
| Placeholder | Generates |
|---|---|
| {{fake.email}} | Random email address (e.g. john.doe@example.com) |
| {{fake.username}} | Random username |
| {{fake.password}} | 8–16 character password with mixed chars |
| {{fake.name}} | Full name |
| {{fake.firstname}} | First name only |
| {{fake.lastname}} | Last name only |
| {{fake.word}} | Single lorem word |
| {{fake.sentence}} | Lorem sentence (3–8 words) |
| {{fake.paragraph}} | Lorem paragraph (1–3 sentences) |
| {{fake.company}} | Company name |
| {{fake.city}} | City name |
| {{fake.country}} | Country name |
| {{fake.uuid}} | UUID v4 |
| {{env.VAR_NAME}} | Value of environment variable VAR_NAME |
Unknown placeholders produce a warning and are left unchanged in the output so they are easy to spot.
Setup phase
The top-level setup array in blast.config.json lists endpoints that run once in order before any load traffic. Extracted values from setup steps are shared with every subsequent request for the entire test.
If a setup step fails (wrong status code, network error), blast aborts immediately rather than firing load with a broken context. This prevents sending thousands of requests with a missing auth token.
The canonical use case is authentication: add a login endpoint to setup, extract the access token with extract, then include it in every load endpoint via the global headers using {{token}}.
Request chaining
The extract field on any endpoint stores response values in a shared context map keyed by variable name. Later endpoints reference them with {{name}} in any string field — headers, body values, or URL path parameters.
The dot-path walker descends into nested JSON objects (data.user.id) and array indices (items.0.id). Only scalar values (strings, numbers, booleans) are stored — objects and arrays emit a warning and are skipped.
{
"name": "login",
"method": "POST",
"path": "/api/v1/auth/login",
"body": { "email": "admin@example.com", "password": "Admin1234!" },
"expect_status": 200,
"extract": {
"token": "data.access_token",
"user_id": "data.user.id"
}
}{
"name": "get user",
"method": "GET",
"path": "/api/v1/users/{{user_id}}",
"headers": { "Authorization": "Bearer {{token}}" },
"expect_status": 200,
"tags": ["run"]
}Values extracted during setup are available to all subsequent endpoints. Values extracted during load operations are available to later endpoints in the same request round.