Skip to content

JMeter Programmatic and DSL Test Plans

Build JMeter plans as code with the 5.6 Java and Kotlin DSL: ListedHashTree, Copy Code from GUI, CI-friendly workflows, and code-first vs k6 trade-offs.

Difficulty
advanced
Guide type
how-to
Estimated read time
12 min read
Last verified version
Verified JMeter 5.6

JMeter DSL / Programmatic Plans (Code-First)

Section titled “JMeter DSL / Programmatic Plans (Code-First)”

Teams leaving GUI-centric workflows for tools like k6 often still need JMeter’s protocol breadth or existing JVM skills. JMeter 5.6 introduced experimental APIs and Kotlin/Java DSL helpers to build plans programmatically. This guide summarizes the official Building a Test Plan Programmatically chapter and how to combine it with CLI execution, git, and CI.

DriverHow programmatic plans help
PR reviewDiff Java/Kotlin instead of huge XML
ReuseShare builders for headers, auth, HTTP defaults
Generate many variantsLoops in code create samplers/data
Hybrid teamsGUI for discovery, code for steady-state suites

You can still save/run .jmx; code is another authoring front-end to the same engine.

Official model:

  • Test elements do not form a tree by themselves.
  • Parent/child relationships live in a ListedHashTree.
  • Use ListedHashTree, not plain HashTree, because HashTree does not honour element order and children may shuffle unexpectedly.

From the manual’s Debug Sampler example pattern:

ListedHashTree root = new ListedHashTree();
TestPlan testPlan = new TestPlan();
ListedHashTree testPlanSubtree = root.add(testPlan);
ThreadGroup threadGroup = new ThreadGroup();
threadGroup.setName("Search Order Thread Group");
ListedHashTree threadGroupSubtree = testPlanSubtree.add(threadGroup);
DebugSampler debugSampler = new DebugSampler();
threadGroupSubtree.add(debugSampler);
  1. Create root tree.
  2. Add TestPlan, keep returned subtree.
  3. Add ThreadGroup under plan.
  4. Add samplers under the thread group subtree.

(Your imports and exact setters match the JMeter version JARs on the classpath.)

The manual documents a Copy Code context action on plan elements. It generates code for the element and its children (example shows Kotlin DSL output for an HTTP sampler). Workflow:

  1. Build or record a fragment in GUI.
  2. Right-click → Copy Code.
  3. Paste into your Kotlin/Java project.
  4. Refactor into functions/modules.
  5. Run via code that produces a tree and invokes the engine, or export/save as jmx if your tooling supports it.

This is the fastest bridge for GUI users moving toward code.

The programmatic chapter covers creating a plan with Kotlin DSL (testTree builder style, class references such as TestPlan::class, unary plus for childless elements). Extension functions on TreeBuilder factor common patterns (e.g. a threadGroup helper with default threads/ramp-up).

See the manual sections:

  • Creating a plan with Kotlin DSL
  • Extending the Kotlin DSL

for syntax details and screenshots of generated code.

Similarly, a Java DSL uses testTree with builder lambdas: b.add(Class, consumer) to configure properties and nest children. Prefer this when the team standardizes on Java without Kotlin.

Concernk6JMeter programmatic
LanguageJS/TSJava/Kotlin (+ jmx)
EngineGo binaryJVM JMeter engine
ProtocolsHTTP-centric strengthsBroad JMeter sampler set
Maturity of DSLCentral product focusExperimental helpers in 5.6
Executionk6 runStill jmeter -n or embedded engine

You do not have to abandon JMeter to get reviewable code; you may adopt DSL authoring while keeping CLI reports and distributed mode.

Deep dive comparisons: JMeter vs alternatives.

  1. Discover journeys with recorder/GUI (recorder).
  2. Copy Code for HTTP fragments.
  3. Parameterize with the same property names you use in jmx (threads, host) for CLI parity.
  4. Store sources in git; build a small jar or use jbang/maven exec as you prefer.
  5. Execute load with non-GUI JMeter and HTML dashboard (best practices).
  6. Gate CI on report metrics (CI/CD).

If you only need versioned XML, committing cleaned .jmx with \${__P} is still valid code-adjacent practice.

Programmatic authoring requires JMeter libraries on the module classpath (ApacheJMeter_core, protocol modules you use, etc.). Match versions to the JMeter you run for load. Plugin classes used in code must exist on workers too (plugins).

ModeNotes
Generate jmx, run CLIFamiliar ops path -n -t -l -e -o
Embedded engine in JVMAdvanced; ensure shutdown and result collection
DistributedSame remote testing rules; plan serialization must include all classes

Unit-test that the tree contains expected labels/counts. Smoke-run with 1 thread before performance environments. Experimental APIs deserve characterization tests when you upgrade JMeter.

  1. Using HashTree instead of ListedHashTree → order bugs.
  2. Mixing GUI-only plugins not on CI classpath.
  3. Assuming DSL stability across majors without reading changes.
  4. Forgetting lean-run rules (listeners, CLI) because “it’s code now.”
  5. Duplicating secrets in source; still use env/__P patterns for runtime.

JMeter 5.6 documents it as experimental. Many teams use it successfully but should pin versions and watch release notes.

Yes. Programmatic APIs are optional. Versioned jmx plus CLI remains fully supported.

Choose based on team language. Both are documented. Copy Code often emits Kotlin DSL examples in the manual screenshots.

Does code-first remove the need for non-GUI mode?

Section titled “Does code-first remove the need for non-GUI mode?”

No. Real load still should run non-GUI with minimal listeners regardless of how the plan was authored.

Rebuild scenarios with HTTP samplers or Copy Code from a recorded flow; map checks to assertions; run CLI reports. Protocol-only k6 scripts map cleanly; browser-level k6 features do not.

In the JMeter GUI context menu on a tree element (documented with screenshot in the programmatic chapter).

On this page