# Loadr – a Rust load-testing tool that began as a single Claude prompt

> Source: <https://loadr.io>
> Published: 2026-06-30 10:05:57+00:00

#
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 →](#credits)

### 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.

[View all 22 demos →](/demos/)

### 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, 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.

### 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](/docs/plugins/overview.html) — 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, 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](#credits).

| 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

## 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 →](/docs/credits.html)

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, plus`http.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 (Locust`catch_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

``` bash
$ 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

# 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
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 →](/examples/)

## 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.
