Experimental build. loadr — the software and this entire site — was designed and built by Anthropic's Fable model as an experiment in AI-driven engineering.
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
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 →
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 RPS. Every latency is an HDR histogram: p(99.9) is exact, never estimated, never averaged.
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.
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
Every clip is the actual loadr binary executing against a live server.
Live charts, threshold pills, run controls, editor and fleet view — a real browser session.
Everything, in the box
If it's listed, it ships in the binary — and every item links to its documentation.
constant-vus, ramping-vus, constant-arrival-rate, ramping-arrival-rate, per-vu-iterations, shared-iterations, externally-controlled — identical semantics, open and closed models.
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.
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.
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.
JSONPath, regex capture groups, XPath 1.0, CSS selectors, boundary extractors and headers — extracted values flow into later requests as ${name} and into JS.
CSV & JSON feeders with sequential, random or shuffle strategies (shared or per-VU, recycle or stop-at-EOF), inline rows, and secrets that never reach logs.
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.
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.
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.
Constant, uniform-random and gaussian think time; constant-throughput pacing (the JMeter timer, done right); per-scenario and global defaults.
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.
Automatic per-VU RFC 6265 cookie jars with manual override, redirect policies, JSON/form/multipart/file bodies, query params — everything interpolated.
Custom CAs, client certificates, SNI override, insecure mode for staging, HTTP/HTTPS proxies (CONNECT), ALPN negotiation with version forcing — all rustls, no OpenSSL.
One file, many targets: loadr run -e staging deep-merges named overlays — gentler CI load, staging URLs, relaxed thresholds, without copy-paste.
JSON lines, CSV, Prometheus (scrape + remote-write), InfluxDB line protocol, OpenTelemetry OTLP (gRPC & HTTP), StatsD — plus a pre-built Grafana dashboard in the repo.
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.
Controller + agents over gRPC with optional mTLS: load partitioning, synchronized starts, data-file shipping, heartbeats, reconnection, agent-loss policies — and central HDR merging.
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.
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.
k6-style console summaries, JSON export, self-contained HTML reports (loadr report), shell completions, JSON Schema output, structured logs, --quiet/-v spectrum.
Show me
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
Every protocol reports DNS, connect, TLS, TTFB, duration, and bytes sent/received — and works with the same extract/assert/check blocks.
- 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.
- request:
url: wss://chat.example.com/ws
ws:
send: [ '{"type":"hello"}' ]
receive_until: '"ack"'
session_duration: 10s
Subprotocols, binary frames, message counters, session metrics.
- 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.
- 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.
- 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.
- 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
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.
agents.replicas=10 and goManagement UI
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.
Save, edit and validate YAML in the browser — diagnostics jump to the line.
Every run's full summary persisted: trends, checks, thresholds, pass/fail.
Agent health, active VUs, cores, labels, last heartbeat — at a glance.
HTTP Basic and bearer tokens; loopback-only by default. JSON API for everything.
How loadr compares
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 |
| 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
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.
The 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').
JMeter 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 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'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
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.
http.batch and an async event loop / timers.atOnceUsers, nothingFor, stepped ramps), and throughput-shaping profiles that adjust concurrency to hold a target RPS.loadr record — capture real browser/API traffic and generate a test.catch_response-style).--expect-workers gating and custom controller↔agent messages.Want something prioritised? It probably came from k6, JMeter, Gatling or Locust — tell us which workflow you're missing.
Install
$ 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 →
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.