#
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)
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
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 — k6-compatible.
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.
Checks + JMeter assertions
k6-style checks that never fail requests, and JMeter-style 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.
Embedded JavaScript
QuickJS per VU with k6-style imports (k6/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.
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, /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.
Reports & tooling
k6-style 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=10
and 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, , 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 + s | 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 |
| 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 modelThe execution model is k6's: the seven executors, open/closed load, the four metric types, thresholds with abortOnFail
and exit code 99, checks and groups — and an embedded-JS experience so close the API is import-compatible (import http from 'k6/http'
).
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: k6's model and JMeter's arsenal and Gatling's DSL and Locust's behaviour model — 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.batch
and 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-workers
gating 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.
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
bash
$ cargo install --git \
https://github.com/levantar-ai/loadr loadr-cli
bash
$ 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.