Migrating from JMeter

loadr convert test-plan.jmx -o converted.yaml
loadr validate converted.yaml
loadr run converted.yaml

The converter parses JMeter 5.x plans and emits clean YAML, with a warning for every element it couldn't translate (disabled elements, plugins, ${__functions}, complex controllers).

Concept map

JMeterloadr
Thread Group (threads, ramp-up, duration)scenario: constant-vus / ramping-vus
Thread Group with loop countper-vu-iterations
Multiple Thread Groupsmultiple scenarios (run concurrently)
HTTP Request samplerrequest: step
HTTP Header Managerheaders: (request- or defaults-level by scope)
HTTP Cookie Managerdefaults.http.cookies: true (default)
CSV Data Set Configdata: block
User Defined Variablesvariables:
Constant / Uniform / Gaussian Random Timerthink_time: (same three types)
Constant Throughput Timerpacing: (per-minute → per-second)
Response Assertionassert: status / body_contains / body_matches
Duration / Size Assertionassert: duration / size
JSON / XPath Assertionassert: jsonpath / xpath
Regular Expression Extractorextract: regex (incl. match no. → index)
JSON / XPath / Boundary Extractorextract: jsonpath / xpath / boundary
CSS Selector Extractorextract: css
Transaction Controllergroup: step
Loop Controllersteps replicated (≤10) or warning
Backend Listener (InfluxDB/Graphite)outputs: influxdb / prometheus / statsd
Aggregate Report / HTML dashboardconsole summary + loadr report + web UI
Distributed testing (RMI, jmeter-server)loadr controller / loadr agent (gRPC, mTLS)
BeanShell / JSR223 / Groovyembedded JavaScript

What changes for the better

  • Percentiles are exact (HDR histograms), including across the fleet — JMeter's distributed mode ships raw samples or averages, loadr merges histograms.
  • Open-model load: JMeter's thread-based model can't hold a target request rate when the system slows down; constant-arrival-rate can.
  • Code review-able tests: YAML diffs instead of 4000-line XML.
  • No JVM tuning, no plugin manager, one binary.

What needs hand-porting

  • JMeter plugins (custom samplers etc.) → loadr protocol plugins.
  • ${__time()}, ${__Random()}, ${__UUID()} and friends → ${js: ...} one-liners (Date.now(), Math.random(), crypto.uuidv4()). The converter flags each occurrence.
  • If/While/Switch controllers → JS scenario functions (exec:), where real control flow is natural.
  • Module/Include controllers → split scenarios across files and compose with environments or separate tests.