Find the
breaking point.
loadr brings together the best ideas from k6, JMeter, Gatling and Locust in one place: declarative YAML tests, embedded JavaScript, six protocols, plugins, a built-in live web UI, and distributed execution with mathematically exact percentiles. All in one binary.
live-demo — 1 scenario(s), 8.1s
checks........................: 100.00% — ✓ 752 ✗ 0
✓ status is 200 (376 / 376)
✓ under 200ms (376 / 376)
http_req_duration.............: avg=4.96ms med=3.02ms p(95)=10.73ms p(99)=49.38ms
http_req_tls_handshaking......: avg=0µs (connections reused per VU)
http_req_waiting..............: avg=4.85ms med=2.90ms p(95)=10.57ms
http_reqs.....................: 376 (46.66/s)
iterations....................: 376 (46.66/s)
vus...........................: value=5 min=4 max=5
thresholds:
✓ http_req_duration: p(95)<500 (observed: 10.73)
✓ checks: rate>0.95 (observed: 1.00)
✓ http_req_failed: rate<0.01 (observed: 0.00)
Desktop app · new
The whole engine, on your desktop.
loadr Desktop is a native GUI over the bundled engine — compose tests in a forms-first editor, run them locally, and watch percentiles, throughput and errors update live. Same binary as the CLI. No terminal required.
- ▸ Forms-first editor + live Monaco YAML
- ▸ Live run cockpit: req/s, p95, errors
- ▸ Run history & compare
- ▸ Signed plugins, one click
Free · SHA-256 checksums · SLSA build provenance on every download
Why loadr
Four tools' best ideas. One Rust binary.
loadr draws, with thanks, on four projects that shaped load testing: k6's execution model, JMeter's request arsenal, Gatling's flow-control DSL and feeders, and Locust's behaviour model — brought together and reimplemented in Rust. See what we built on →
Honest load, honest numbers
Open-model arrival-rate executors keep the offered load constant even when your
system slows down — saturation shows up as dropped_iterations,
not silently lower throughput (requests per second, RPS). Every latency is an HDR histogram: p(99.9) is exact, never estimated, never averaged.
Tests you can code-review
Declarative YAML with a generated JSON Schema — your editor autocompletes it,
loadr validate lints it with line numbers and
did-you-mean fixes, and the diff in your PR actually means something.
Drop into JavaScript exactly where logic demands it.
A platform, not just a CLI
Built-in management web UI (think RabbitMQ for load tests), distributed
controller/agent mode over mTLS gRPC, six metric exporters, WASM & native plugins,
and importers that eat your existing .jmx plans and k6 scripts.
See it in action
Real recordings. Real runs. No mockups.
Every clip is the actual loadr binary executing against a live server.
The live web UI, mid-run
Live charts, threshold pills, run controls, editor and fleet view — a real browser session.
The quickstart 0:24
A distributed fleet, live 0:34
Built in, not bolted on
Commands the other tools don't have.
Recording, generation, analysis and adversarial testing — one binary, one specialist doing all of it.
Session recorder
loadr record — a capturing HTTP(S) proxy that emits a ready-to-run scenario with tokens and ids auto-correlated.
Generate from a contract
loadr gen turns OpenAPI, Postman, GraphQL or gRPC into a runnable plan — --fuzz adds adversarial variants.
AI copilot
loadr scenario writes a validated plan from a sentence; loadr explain reads a run back in plain language.
Regression intelligence
loadr history flags statistical regressions with a robust median/MAD z-score — one noisy CI run can't false-alarm.
Payload Lab
loadr payload + sweep --complexity generates adversarial input and fits the exponent — a DoS finder in one command.
…and a desktop app
A native GUI over the same engine — compose visually, run locally, watch percentiles live. See it →
Everything, in the box
The exhaustive feature list
If it's listed, it ships in the binary — and every item links to its documentation.
All 7 k6 executors
constant-vus, ramping-vus, constant-arrival-rate, ramping-arrival-rate, per-vu-iterations, shared-iterations, externally-controlled — identical semantics, open and closed models.
Concurrent scenarios
Any number of named scenarios per test with independent executors, stages, start times, graceful stop and ramp-down — browsers, API clients and batch jobs in one run.
Thresholds as CI gates
p(95)<400, rate>0.99, any percentile, tag-filtered selectors, abort_on_fail circuit breakers with warm-up delay. Exit code 99 on failure.
SLO error budgets
slo(99.9%) < 300ms — thresholds written the way SLOs are. Objectives at 50/90/95/99/99.9 map to exact HDR percentiles and gate CI like any other threshold, but read like the contract they enforce.
CI-native: GitHub Action + JUnit
A first-party setup-loadr / run action installs the CLI and runs your plan, and --junit emits a JUnit report every CI test panel renders — GitHub, GitLab, Jenkins, CircleCI.
Run-over-run comparison
loadr compare base.json current.json diffs two runs with direction-aware regression detection, writes a markdown table for PR comments, and with --assert exits 99 when --max-regression p95=10% is blown.
Parameter sweeps
loadr sweep plan.yaml --var vus=10,50,100 runs one plan across a matrix — repeat --var and the axes multiply — then tabulates p50/p95/p99, error rate and RPS per combination, on the terminal or as markdown.
Payloads & complexity testing
loadr payload generates adversarial input — nested JSON/markdown, billion-laughs, ReDoS, hash-collision and more. Scale it with sweep --complexity and loadr fits the exponent: O(n^1.6) ⚠ exits 99 when a parser scales super-linearly. A DoS finder in one command.
Session recorder
loadr record is a capturing HTTP(S) proxy — drive your app through it and it emits a ready-to-run scenario with tokens, CSRF and ids auto-correlated. HTTPS via an install-once local CA. No devtools HAR dance.
Generate from a contract
loadr gen openapi|postman|graphql|grpc turns an API contract into a runnable scenario — one request per operation, params and bodies from the schema. --fuzz adds spec-invalid & adversarial variants gated on never a 5xx.
AI copilot
loadr scenario "500 rps on /checkout for 10m" generates a validated plan (Anthropic). And loadr explain summary.json gives a deterministic, no-model root-cause read — saturation vs a slow path vs healthy.
History & regression detection
loadr history records every run in a local SQLite store and flags statistical regressions — a robust median/MAD z-score against a window, so one noisy CI run can't false-alarm. Exit 99 gates the merge.
Checks + JMeter assertions
Non-blocking checks that never fail requests, plus hard assertions that do: status, body contains/regex, JSONPath, XPath, duration, size, headers, JS expressions — with abort actions.
Correlation & extraction
JSONPath, regex capture groups, XPath 1.0, CSS selectors, boundary extractors and headers — extracted values flow into later requests as ${name} and into JS.
Data-driven testing
CSV & JSON feeders with sequential, random or shuffle strategies (shared or per virtual user (VU), recycle or stop-at-EOF), inline rows, and secrets that never reach logs.
Flow control & weighted tasks
repeat, while, if/else and weighted / uniform / round-robin random branches — Gatling's loops and switches and Locust's weighted-task model, in declarative YAML.
Throttling
A global request-rate ceiling (throttle: { requests_per_second }) on top of any executor — Gatling's reachRps, for staying under a known rate limit no matter how fast the target is.
Fault injection
A faults: block degrades the traffic loadr generates — latency jitter (uniform or gaussian) and a request drop_rate — so you can rehearse the bad day from the load generator, with nothing installed on the target.
Embedded JavaScript
QuickJS per VU with a native module API (loadr/http, check, sleep, metrics), setup()/teardown(), scenario functions, beforeRequest/afterRequest hooks, inline ${js: …} — sandboxed with time & memory limits.
Timers & pacing
Constant, uniform-random and gaussian think time; constant-throughput pacing (the JMeter timer, done right); per-scenario and global defaults.
Phase-level HTTP timings
DNS, connect, TLS handshake, send, TTFB and receive measured per request on a hand-built hyper stack — plus exact wire-level byte counts. No averaged guesses.
Cookies, redirects, bodies
Automatic per-VU RFC 6265 cookie jars with manual override, redirect policies, JSON/form/multipart/file bodies, query params — everything interpolated.
TLS, mTLS, proxies, HTTP/2+
Custom CAs, client certificates, SNI override, insecure mode for staging, HTTP/HTTPS proxies (CONNECT), ALPN negotiation with version forcing — all rustls, no OpenSSL.
Environment overlays
One file, many targets: loadr run -e staging deep-merges named overlays — gentler CI load, staging URLs, relaxed thresholds, without copy-paste.
6 metric exporters
JSON lines, CSV, Prometheus (scrape + remote-write), InfluxDB line protocol, OpenTelemetry OTLP (gRPC & HTTP), StatsD — plus a pre-built Grafana dashboard in the repo.
System correlation
An observe: system source samples host CPU, memory, disk and network alongside the load — system_cpu lands on the same timeline as latency and can gate thresholds (max<0.9) like any other metric.
WASM + native plugins
Five plugin types (protocol, output, extractor, assertion, service) over two mechanisms: sandboxed WASM components with a WIT interface, and abi_stable native libraries. No rebuilds, ever.
Distributed by design
Controller + agents over gRPC with optional mTLS: load partitioning, synchronized starts, data-file shipping, heartbeats, reconnection, agent-loss policies — and central HDR merging.
Built-in web UI
Live dashboards over SSE, a test editor with one-click validation, run history, pause/stop/scale controls, agent fleet view, log tail — embedded in the binary, dark mode native.
JMeter & k6 importers
loadr convert plan.jmx translates thread groups, samplers, timers, assertions, extractors and CSV configs; the k6 importer maps options, scenarios, checks and http calls — with clear warnings for the rest.
Traffic replay from logs
loadr convert access.log turns a combined-format access log into a runnable plan: the observed arrival rate as a constant-arrival-rate executor over a weighted mix of your real top endpoints.
Reports & tooling
Rich console summaries, JSON export, self-contained HTML reports (loadr report), shell completions, JSON Schema output, structured logs, --quiet/-v spectrum.
Show me
From smoke test to fleet-scale in the same file
name: checkout-under-load
defaults:
http: { base_url: https://shop.example.com }
data:
users: { type: csv, path: users.csv, mode: shared, on_eof: recycle }
scenarios:
shoppers:
executor: ramping-vus
stages: [ { duration: 2m, target: 100 }, { duration: 5m, target: 100 } ]
think_time: { type: uniform, min: 1s, max: 3s }
flow:
- request:
url: /login
method: POST
body: { form: { user: "${data.users.username}", pass: "${data.users.password}" } }
extract:
- { type: css, name: csrf, expression: "input[name=csrf]", attribute: value }
assert:
- { type: status, equals: 200 }
- request:
method: POST
url: /cart
body: { form: { sku: W-1, csrf: "${csrf}" } }
checks:
- { type: status, equals: 201 }
- { type: duration, name: fast checkout, max: 300ms }
thresholds:
http_req_duration: [ "p(95)<400", "p(99.9)<1500" ]
http_req_failed: [ { threshold: "rate<0.01", abort_on_fail: true } ]
checks: [ "rate>0.99" ]
Protocols
Six protocols. Full metrics on every one.
Every protocol reports DNS, connect, TLS, TTFB, duration, and bytes sent/received — and works with the same extract/assert/check blocks.
HTTP/1.1 + 2
- request:
method: POST
url: /orders
body: { json: { sku: W-1, qty: 2 } }
checks: [ { type: status, equals: 201 } ]
ALPN, prior-knowledge h2, keep-alive tuning, per-VU pools.
WebSocket
- request:
url: wss://chat.example.com/ws
ws:
send: [ '{"type":"hello"}' ]
receive_until: '"ack"'
session_duration: 10s
Subprotocols, binary frames, message counters, session metrics.
gRPC
- request:
url: grpc://svc:50051
grpc:
reflection: true # or proto_files
service: helloworld.Greeter
method: SayHello
message: { name: "vu-${vu}" }
Unary + all streaming shapes, in-process proto compile — no protoc.
GraphQL
- request:
url: /graphql
protocol: graphql
graphql:
query: "query($t:String!){ search(t:$t){ id } }"
variables: { t: widget }
GraphQL error semantics, partial-error awareness, own metric family.
TCP
- request:
url: tcp://gateway:7000
socket:
send_text: "PING\r\n"
read_bytes: 64
checks: [ { type: body_contains, value: PONG } ]
Exact byte accounting; regex/boundary extraction over raw payloads.
UDP
- request:
url: udp://stats:8125
socket:
send_hex: "deadbeef 0102"
read_timeout: 500ms
Datagram round trips with hex payloads and loss-aware timeouts.
Need MQTT, Kafka, or your in-house protocol? Write a protocol plugin — no fork, no rebuild.
Distributed
Most tools average percentiles across nodes. That number is wrong.
If agent A's p99 is 100 ms and agent B's is 1000 ms, the fleet's true p99 is not 550 ms. loadr agents stream HDR histogram deltas every second; the controller merges the histograms — a lossless operation — and computes percentiles only after the merge. Thresholds evaluate centrally against fleet-wide truth.
- ▸ VU counts and arrival rates partitioned exactly across agents — global ramps stay precise
- ▸ Synchronized start barrier, heartbeats, jittered reconnection, agent-loss policies
- ▸ Test definitions and CSV/proto/JS files shipped to agents automatically
- ▸ One bidirectional gRPC stream per agent, plaintext or mTLS
- ▸ Docker Compose stack and Helm chart in the repo:
agents.replicas=10and go
partition · merge · thresholds · UI
200 rps
200 rps
200 rps
Management UI
RabbitMQ-style management, for load tests
Embedded in the binary. loadr run --ui for a single run, or the full fleet console on the controller. Edit and validate tests in the browser, watch live percentiles, pause, stop, or turn the VU dial mid-run.
Test library & editor
Save, edit and validate YAML in the browser — diagnostics jump to the line.
Run history
Every run's full summary persisted: trends, checks, thresholds, pass/fail.
Fleet view
Agent health, active VUs, cores, labels, last heartbeat — at a glance.
Auth built in
HTTP Basic and bearer tokens; loopback-only by default. JSON API for everything.
How loadr compares
loadr next to k6, JMeter, Gatling & Locust
All four are excellent, widely-loved tools that shaped this space — this is simply where loadr sits relative to them; pick whatever fits your team. Where a cell says Enterprise or cloud, the capability exists in that project's paid/hosted tier. See also what loadr is built on.
| k6 | JMeter | Gatling | Locust | loadr | |
|---|---|---|---|---|---|
| Test format | JavaScript | XML (GUI) | Scala / Java / Kotlin DSL | Python | YAML + JS, JSON-Schema validated |
| Open-model load (arrival rate) | ✓ | plugin | ✓ injection profiles | custom shapes | ✓ all 7 executors |
| Protocols built in | HTTP, WS, gRPC | many | HTTP, WS, SSE, JMS | HTTP (custom clients) | HTTP/1.1+2, WS, gRPC + reflection, GraphQL, TCP, UDP |
| Assertions / extractors / timers | checks | ✓ full | checks + pauses | in Python | ✓ JSONPath, XPath, CSS, regex, boundary; 3 timers + pacing |
| Flow control & feeders (Gatling-style) | code | controllers | ✓ DSL | in Python | ✓ repeat/while/if/switch/foreach + feeders + throttle |
| Extensions without rebuilding | — (xk6 recompile) | jars | — (Scala recompile) | Python | ✓ WASM (sandboxed) + native plugins |
| Distributed execution | cloud | RMI | Enterprise | ✓ master / worker | ✓ built-in, gRPC + mTLS |
| Fleet-wide percentiles | cloud | averaged | Enterprise | approximate | ✓ exact (HDR histogram merge) |
| Live management UI | cloud | — | Enterprise | ✓ built-in | ✓ embedded |
| Per-phase timings (DNS/TLS/TTFB) | ✓ | partial | ✓ | — | ✓ on every protocol |
| Run comparison + PR gating | cloud | — | Enterprise | — | ✓ loadr compare --assert, markdown for PR comments |
| Parameter sweep matrix | scripted | — | — | scripted | ✓ loadr sweep --var vus=10,50,100 |
| SLO budgets | partial (p(N) thresholds) | — | partial (percentile assertions) | — | ✓ slo(99.9%) < 300ms |
| System metrics on the timeline | — (external Grafana) | plugin (PerfMon) | Enterprise | — | ✓ observe: system, CPU/mem on the run timeline |
| Traffic replay from access logs | — | partial (log sampler) | — | — | ✓ converts to a weighted arrival-rate plan |
| Fault injection | extension (k8s disruptor) | — | — | in Python | ✓ latency jitter + request drops |
| Runtime footprint | Go binary | JVM + tuning | JVM | Python runtime | one Rust binary, distroless image |
| Migration path in | — | — | — | — | ✓ imports .jmx and k6 scripts |
Standing on shoulders
What loadr is built on
loadr is a fresh Rust implementation — not a fork of anything — but it takes the best ideas from four tools that defined load testing, deliberately and with thanks.
k6
the modelloadr's execution model gives you the seven executors, open/closed load, the four metric types, thresholds with abortOnFail and exit code 99, checks and groups — with a native embedded-JS API (import http from 'loadr/http'). Coming from k6? loadr convert brings your scripts across unchanged.
Apache JMeter
the arsenalJMeter shaped the request toolkit: response / duration / size / JSONPath / XPath assertions; regex, boundary, CSS and XPath extractors; constant / uniform / gaussian and constant-throughput timers; CSV data sets and cookie management. loadr convert reads your .jmx plans.
Gatling
the DSLGatling gave loadr its flow control — repeat, while, if/else and the random / uniform / round-robin switch — plus feeder strategies (sequential / random / shuffle), JSON feeders, and the request-rate throttle.
Locust
the behaviour modelLocust's weighted-task model — users picking @task(weight) actions at random — is exactly loadr's weighted random step. Its clean real-time UI inspired loadr's management UI, and its master/worker model informed the controller/agent design.
The combination is the point: everything you'd reach for k6, JMeter, Gatling or Locust to do — scriptable execution and a deep assertion arsenal and a flow-control DSL and weighted-behaviour modelling — in one binary, with correct distributed percentiles, a plugin system and six protocols, rarely found together in a single tool. Full credits →
Trademarks and project names belong to their respective owners. loadr is independent and not affiliated with or endorsed by k6/Grafana Labs, the Apache Software Foundation, Gatling Corp, or the Locust project.
Roadmap
What's coming
loadr already covers the core of k6, JMeter, Gatling and Locust. Here's where it's headed next — shaped by what those tools and their plugin ecosystems do that loadr doesn't yet. No dates, just direction; priorities shift with feedback.
Just shipped: SQL load testing (PostgreSQL & MySQL), the time-series HTML report, JMESPath & fused check-chains, and the in-UI failure & error breakdown.
Next up
- Scriptable protocol clients in JS
Drive WebSocket and gRPC from JavaScript, plushttp.batchand an async event loop / timers. - Server-side resource monitoring
Correlate CPU / memory / disk / network of the system-under-test with your load — JMeter's PerfMon, built in. - Programmable load shapes
Compute load per-tick in code, richer injection profiles (atOnceUsers,nothingFor, stepped ramps), and throughput-shaping profiles that adjust concurrency to hold a target RPS.
Planned
- Proxy recorder
loadr record— capture real browser/API traffic and generate a test. - Manual pass/fail from JS
Mark a response failed/succeeded in script (Locustcatch_response-style). - Messaging protocols
Kafka, MQTT, JMS and AMQP — likely as plugins on the existing plugin ABI. - Inter-VU coordination & auto-stop
Pass data between virtual users at runtime, and stop a run automatically when error-rate or latency guards trip.
Exploring
- Managed outputs & dashboards
More exporters and hosted run-over-run trend comparison. - Distributed niceties
--expect-workersgating and custom controller↔agent messages. - Plugin registry
A browsable catalog of community WASM & native plugins.
Want something prioritised? It probably came from k6, JMeter, Gatling or Locust — tell us which workflow you're missing.
Break things on purpose.
Drive real load, adversarial payloads and fault injection at your system — from one binary — and find the limit before your users do.
Install
Running in under a minute
$ curl -sSL https://github.com/levantar-ai/loadr/releases/latest/download/loadr-x86_64-unknown-linux-gnu.tar.gz | tar xz
$ sudo mv loadr-*/loadr /usr/local/bin/
$ loadr version
$ cargo install --git \
https://github.com/levantar-ai/loadr loadr-cli
# no system deps: no protoc,
# no OpenSSL, no JVM, no node
# macOS (Intel + Apple Silicon), Windows,
# Linux x86_64 + arm64 — every build, with
# SHA256 checksums and SLSA provenance:
# github.com/levantar-ai/loadr/releases
$ loadr validate examples/01-quickstart.yaml # line-numbered diagnostics, did-you-mean fixes
$ loadr run examples/01-quickstart.yaml # exit 0 = thresholds passed, 99 = failed
$ loadr run --ui examples/02-ramping-load.yaml # live dashboard at http://127.0.0.1:6464
$ loadr report results.json -o report.html # self-contained HTML report
27 runnable examples ship in the examples/ folder of every download —
ramp, spike and soak tests, data-driven logins, WebSocket chat, gRPC streaming, GraphQL, Redis, SSE,
headless-browser timing, raw sockets, environment overlays and a distributed fleet test.
Browse all 34 →
The documentation is exhaustive.
A getting-started path, the complete YAML reference, the full JS API, every protocol, distributed operations, plugin development with worked examples, and k6 and JMeter migration guides — everything you need to go from zero to a production load test.