What’s Changed & Migration
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. |
The reference material consulted while preparing these pages is listed in the section bibliography.
Most of what is written about JMeter, including the three books this section draws on, describes JMeter 2.11, 2.12 or
3.0. The test-plan model has not changed since then: thread groups, samplers, config elements, timers, extractors,
assertions and listeners still run in the same order and with the same scoping rules. What changed is almost
everything around that model: the scripting language, the JSON and XML tooling, the way plugins are installed, how
results are reported and monitored, how distributed runs are secured, and the Java version underneath. This page
collects those changes in one place. It gives a timeline, a release-by-release summary, a table that maps each book
idiom to its current replacement, a measured procedure for migrating an old .jmx file and a checklist for the next
major version. The topic pages linked from each row carry the detail.
The page was written against Apache JMeter 5.6.3 (released 2024-01-07), the latest release on 2026-10-14. JMeter 6.0
is not released. On that date the download page offered 5.6.3, the newest tag in the apache/jmeter repository
was v5.6.3-rc2, and the newest ApacheJMeter_core artifact on Maven Central was 5.6.3. The master branch declares
version 6.0.0, and its xdocs/changes.xml lists what 6.0 is planned to contain. Everything said here about 6.0 is
planned, not released behaviour, and may change before the release. Other versions used on this page are Java 17 or
later (21 recommended; 5.6.3 itself runs on Java 8 or later), Groovy 3.0.20 as bundled with 5.6.3, JMeter Plugins
Manager 2.0, jmeter-maven-plugin 3.8.0, the gRPC Request plugin 2.0.x and JMeter Java DSL 2.3. The legacy-plan runs
shown below were made on a real 5.6.3 installation with Java 21.
Where the facts come from
Every version claim on this page comes from one of four official sources. Use them to re-check a claim when you upgrade.
| Source | What it contains | Use it for |
|---|---|---|
Release notes for every version from 2.3.3 to 5.6.2: "New and Noteworthy", "Incompatible changes", removed elements, bug and improvement lists, dependency upgrades. |
When a feature appeared and when an element was deprecated or removed. |
|
The notes of the current release, 5.6.3, and the Java requirement ("JMeter 5.6.x requires Java 8 or later for execution (Java 17 or later recommended)"). |
What the release you run contains. |
|
The change log of the unreleased 6.0.0: incompatible changes, changes, library upgrades and bug fixes. |
Preparing for 6.0. It describes the development branch, not a release. |
|
The current binary and source archives with SHA-512 checksums and PGP signatures. |
Confirming which version is the latest. |
Release dates on this page are the publication dates of the release artifacts in the Apache archive and on Maven Central. The change logs themselves do not date most releases.
A quick way to check whether a newer release exists is to ask Maven Central for the newest ApacheJMeter_core
version:
curl -s https://repo1.maven.org/maven2/org/apache/jmeter/ApacheJMeter_core/maven-metadata.xml \
| grep -E '<latest>|<release>|<lastUpdated>'
Output on 2026-10-14:
<latest>5.6.3</latest>
<release>5.6.3</release>
<lastUpdated>20240107170103</lastUpdated>
Source: Download Apache JMeter
Version timeline
The books cover the top of the timeline: JMeter Cookbook uses 2.11, Performance Testing with JMeter (2nd ed.) uses 2.12 and Pro Apache JMeter uses 3.0. Everything below 3.0 in the timeline is newer than all three books.
Release by release
The tables below keep only the changes that alter how a plan is written, run or read. Each change links to the page that explains the element today. Dependency bumps and bug fixes are left out unless they change behaviour.
The books' baseline: 2.11 to 3.0
| Version | Released | Changes that matter for plans written today |
|---|---|---|
2.11 |
January 2014 |
The version of JMeter Cookbook. The summariser is on by default in non-GUI mode. New Transaction Controllers exclude timer and pre/post-processor time by default (see Logic Controllers & Transactions). |
2.12 |
November 2014 |
The version of Performance Testing with JMeter. Adds the Critical Section Controller, JMS Priority and Expiration, SMTP timeouts and the Synchronizing Timer timeout. |
2.13 |
March 2015 |
Adds the asynchronous Backend Listener with a Graphite client, the ancestor of today’s real-time monitoring (see Real-time Monitoring with Backend Listener). Test Fragments are disabled by default. The WebService(SOAP) Request is deprecated. |
3.0 |
May 2016 |
The version of Pro Apache JMeter. Requires Java 7. Adds the HTML dashboard report ( |
3.1 to 3.3: Groovy first, Java 8, Log4j 2
| Version | Released | Changes |
|---|---|---|
3.1 |
November 2016 |
Groovy becomes the default JSR223 language and the |
3.2 |
April 2017 |
Requires Java 8 (Java 7 support dropped). Logging moves to SLF4J and Log4j 2 with |
3.3 |
September 2017 |
InfluxDB over UDP and error counts per response code, TCP Sampler latency, JDBC driver and validation-query
drop-downs, the |
4.0: the WorkBench goes, SSL comes
Released February 2018. This is the release that breaks the most book instructions.
| Change | Detail |
|---|---|
WorkBench removed |
Non-test elements (the HTTP(S) Test Script Recorder, Mirror Server, Property Display) become direct children of the Test Plan. When an old plan is loaded, JMeter moves those three elements under the Test Plan and puts any other WorkBench content in a Test Fragment called Workbench Test Fragment. Recording starts from the Recording template (see Recording & cURL Import). |
RMI over SSL by default |
"Since JMeter 4.0 the default transport mechanism for RMI will use SSL": create a keystore with
|
New core elements |
Boundary Extractor, JSON Assertion (the AtlantBH JSON Path Assertion migrated from jmeter-plugins) and Precise Throughput Timer (Poisson arrivals at a constant throughput). See Correlation & Extractors, Assertions and Open Model & Throughput Control. |
Safer defaults |
New If Controllers interpret the condition as a variable expression, new JSR223 elements cache compiled scripts, and
Loop and ForEach Controllers expose |
Thread Group scheduler |
The absolute Start Time and End Time fields are removed; only Duration and Startup delay remain (see Thread Groups: Concurrent Users & Ramp-up). |
Other |
Java 9 support, the Darcula look and feel by default, |
5.0 to 5.4
| Version | Released | Changes |
|---|---|---|
5.0 |
September 2018 |
XPath2 Extractor. Test Action renamed Flow Control Action and CSS/JQuery Extractor renamed CSS Selector
Extractor. Go to next iteration of Current Loop and Break Current Loop added to the Flow Control Action and the
Result Status Action Handler. HTTP state (connections and SSL) is reset on each thread-group iteration with HttpClient4.
Sub-results are written to CSV results files and renamed with |
5.1 |
February 2019 |
The documentation renames non-GUI mode to CLI mode (the option is still |
5.2 |
October 2019 |
Same user on each iteration on the Thread Group (drives the Cookie Manager, Cache Manager and HTTP state reset). JMESPath Extractor and Assertion, XPath2 Assertion, empty Boundary Extractor boundaries, InfluxDB 2 support, the Bolt Request for Neo4j, PKCS11 keystores, Preinit Pool in the JDBC Connection Configuration. XML parsing refuses insecure XML. |
5.3 |
May 2020 |
Groovy 3.0.3, listed as an incompatible change: "The update to Groovy 3 might break some old Groovy code". The
default |
5.4 |
November 2020 |
GraphQL HTTP Request (see REST, JSON, GraphQL & SOAP APIs).
A Backend Listener client that sends raw results to InfluxDB. The dashboard says PASS and FAIL instead of OK and KO.
cURL import handles backslash line continuations and |
5.4.1, 5.4.2, 5.4.3 |
January and December 2021 |
5.4.2 is a fix release for CVE-2021-44228 (Log4j 2 JNDI lookups) and 5.4.3 for CVE-2021-45105. Any installation older than 5.4.3 ships a vulnerable Log4j 2 and should not be kept around for "compatibility". |
5.5: the open model
Released June 2022. Adds the Open Model Thread Group (experimental), which drives arrivals from a schedule such as
rate(0/sec) random_arrivals(1 min) rate(10/sec) instead of a thread count, and the experimental
jmeter.regex.engine=java switch from Jakarta ORO to the JDK regular expression engine (ORO remains the default in
5.6.3). JMeter now supports Java 17, ships Log4j 2.17.2 and starts using Kotlin in core classes. The GraphQL HTTP
Request accepts variables, the JSON Assertion fails on an indefinite path with an empty result, and the dashboard’s
percentile estimator becomes configurable. See
Open Model & Throughput Control.
5.6 to 5.6.3: the current line
| Version | Released | Changes |
|---|---|---|
5.6 |
June 2023 |
Plugins are found through Java’s |
5.6.1 |
July 2023 |
UTF-8 becomes the default encoding of the HTTP sampler and of |
5.6.2 |
July 2023 |
A single fix for Maven |
5.6.3 |
January 2024 |
|
There is no Groovy 4 release of JMeter: every 5.x release from 5.3 to 5.6.3 bundles Groovy 3, and the planned 6.0 jumps to Groovy 5.1.3. The bundled Groovy version per release is in Scripting with JSR223 & Groovy.
Planned for 6.0 (unreleased)
The xdocs/changes.xml file on the master branch opens with "JMeter 6.x requires Java 17 or later for execution
(Java 21 is recommended)". The planned changes, grouped by what they affect:
| Area | Planned change (changes.xml on master) |
Reference |
|---|---|---|
Runtime |
Java 17 or later required (21 recommended); Kotlin 1.9 or later required for running JMeter. |
PR 6220, PR 6550 |
Removed elements |
MongoDB Script sampler and MongoDB Source Config removed with the bundled |
PR 6573 |
Cookies |
The HTTP Cookie Manager no longer sends cookies after their expiry time (an incompatible change). |
Issue 6428 |
HTTP |
307 and 308 redirects keep the original method; no automatic |
Issues 6080, 6250, 5466; PR 5891 |
Timing |
Delays in the Open Model Thread Group and the Precise Throughput Timer computed from the start of the Thread Group instead of the start of the test. |
Issue 6352 |
Configuration |
References to the MySQL driver change to |
PR 6274, PR 6596 |
Extractors |
The JSON Extractor supports trailing empty default values such as |
Issue 6448 |
Libraries |
Groovy 5.1.3, Apache Tika 4.x (from 1.x), Saxon-HE 13 (from 11), json-path 3.0.0, Neo4j Java driver 6.x, Rhino 1.9.1, jsoup 1.23.2, Jackson 2.22.3, dnsjava 3.6.5, Log4j 2.26.1, Commons libraries; tested against Bouncy Castle 1.86 (not bundled). |
Non-functional changes |
Start-up and reports |
Log4j package scanning removed (the |
Issue 5937, PRs 6620, 6358, 6654 |
GUI |
Automatic HiDPI, recent-file menu synchronised across JVMs, a space after |
PRs 6333, 6509, 6268, 6656 |
One more change is visible on the master branch but not listed in changes.xml yet: the JMS samplers are compiled
against jakarta.jms (Jakarta Messaging 3.1) instead of javax.jms, which means a Jakarta client jar for the
provider. Treat it as planned and re-check it in the 6.0 release notes; see
Messaging: JMS, Mail & TCP.
Outdated book idiom → current practice
The books' methodology still holds; their tooling often does not. Each row names the idiom, where the books use it, its status in 5.6.3 and what to do instead. Chapters refer to JMeter Cookbook (Cookbook), Performance Testing with JMeter 2nd ed. (PTwJ) and Pro Apache JMeter (Pro).
| Book idiom (chapter) | Status in 5.6.3 (and 6.0) | Current practice | Detail |
|---|---|---|---|
BeanShell pre/post-processors (Pro ch. 3) and the BSF PostProcessor (PTwJ ch. 3) |
BeanShell is discouraged by the best-practices page. The BSF elements were deprecated in 3.1; they still ship but are
listed in |
JSR223 elements with Groovy and Cache compiled script if available; no |
|
SOAP/XML-RPC Request and WebService(SOAP) Request samplers (Cookbook ch. 4; PTwJ ch. 7) |
WebService(SOAP) removed in 3.0, SOAP/XML-RPC removed in 3.2. An old SOAP/XML-RPC Request is converted to an empty config element on load, so it silently sends nothing (measured below). |
HTTP Request with the envelope in Body Data, |
|
|
The |
Core JSON Extractor (3.0, renamed in 3.1), JSON Assertion (4.0), JMESPath Extractor and Assertion (5.2), Boundary Extractor (4.0). |
|
Monitor Results listener for Tomcat, and PerfMon with ServerAgent (PTwJ ch. 5; Pro ch. 9) |
Monitor Results removed in 3.2 (an old one loads as an obsolete element). PerfMon is a legacy community plugin. |
Backend Listener to InfluxDB or Graphite for JMeter’s own metrics, and Prometheus (Actuator, Micrometer, exporters) for the server, side by side in Grafana. |
Real-time Monitoring with Backend Listener, Analyzing Results & Finding Bottlenecks |
Stepping Thread Group (Cookbook ch. 6) |
Still in |
Concurrency Thread Group for steps of concurrent users; Arrivals Thread Group or the core Open Model Thread Group (5.5) for arrival rates. |
|
Recording into the WorkBench with the HTTP Proxy Server (Pro ch. 4) |
WorkBench removed in 4.0; old plans are migrated on load. |
File → Templates → Recording, the HTTP(S) Test Script Recorder on port 8888 with the |
|
"Non-GUI mode" (Pro ch. 3) |
Called CLI mode since the 5.1 documentation; same |
|
|
Unzipping the jmeter-plugins Standard and Extras sets (Cookbook appendix) |
The sets are virtual packages in the catalogue today; plugins are installed one by one. |
Plugins Manager 2.0 from Options → Plugins Manager, or |
|
jmeter-maven-plugin 1.10 with plugins declared as Maven plugin dependencies (Cookbook ch. 8; Pro ch. 7) |
1.10.0 added JMeter 2.11 support. 2.0.0 introduced |
jmeter-maven-plugin 3.8.0 with |
Covered later in this section, in the CI/CD page; see also Performance Testing with Apache JMeter |
HttpClient 3.1 implementation (Pro ch. 3, 5) |
Removed in 3.2; an old HttpClient 3.1 sampler loads as an obsolete element. |
Leave Implementation empty (HttpClient4) or choose |
|
Thread Group scheduler with Start Time and End Time (PTwJ ch. 2; Pro ch. 5) |
Start and End Time removed in 4.0. |
Specify Thread lifetime with Duration and Startup delay, driven by |
|
Reports from GUI listeners and plugin graphs (Cookbook ch. 7) |
GUI listeners are for debugging; View Results Tree is capped at 500 entries. |
The HTML dashboard ( |
|
Plain RMI between master and slaves (Pro ch. 6; Cookbook ch. 5) |
RMI over SSL by default since 4.0; |
A shared RMI keystore on every node, data files copied to every node, same JMeter and Java versions everywhere. |
Covered later in this section, in the distributed testing page |
MongoDB Script sampler (Cookbook ch. 4; PTwJ ch. 7) |
Deprecated in 3.0 and hidden; bundled driver 2.14.3. Planned 6.0: removed, plans no longer load. |
JSR223 Sampler with a current MongoDB Java driver in |
|
Typing non-ASCII data with an explicit encoding (Cookbook; Pro) |
UTF-8 is the HTTP default since 5.6.1. |
Leave Content encoding empty unless the server needs something else. |
Migrating a book-era plan to 5.6.3
A plan saved by JMeter 2.x or 3.0 usually opens in 5.6.3, which is exactly the problem: some obsolete elements load without any error and then do nothing. The procedure below finds them before a test result is trusted.
What happens when 5.6.3 loads old elements
Three small plans with book-era elements were run on JMeter 5.6.3 (Java 21) in CLI mode. Each has one thread and one iteration, and none needs a server.
| Plan contains | Exit code | What happened |
|---|---|---|
A Debug Sampler with a BeanShell PostProcessor and a BSF PostProcessor (language |
0 |
The plan ran and the sample passed. The BeanShell script ran. The BSF script did not: |
A SOAP/XML-RPC Request |
0 |
"Created the tree successfully", then |
A |
1 |
|
The relevant lines of the first run:
bin/jmeter -n -t legacy-scripting.jmx -l legacy-scripting.jtl -j legacy-scripting.log
grep -E 'WARN|ERROR' legacy-scripting.log
Created the tree successfully using legacy-scripting.jmx
summary = 1 in 00:00:00 = 12.3/s Avg: 2 Min: 2 Max: 2 Err: 0 (0.00%)
... end of run
2026-10-14 13:31:26,571 ERROR o.a.b.BSFManager: Exception :
2026-10-14 13:31:26,581 WARN o.a.j.e.BSFPostProcessor: Problem in BSF script: org.apache.bsf.BSFException: unable to load language: groovy
The conversions come from bin/upgrade.properties, which maps removed classes (SoapSampler, WebServiceSampler,
HTTPSampler2, MonitorHealthVisualizer and others) to ConfigTestElement or ObsoleteGui, and the hidden elements
come from not_in_menu in bin/jmeter.properties, which in 5.6.3 lists the two MongoDB elements, the six BSF
elements and the SOAP sampler GUI. The lesson: an exit code of 0 and "Created the tree successfully" do not prove that
an old plan does what it did on 2.x.
Step 1: inventory the plans
Because the .jmx format is XML with one element per test element, a plain text search finds the obsolete ones. The
script below reports every match with its line number and the replacement, and exits with 1 when it finds any, so it
can also run in CI before the load test:
#!/usr/bin/env bash
# jmx-legacy-scan.sh: report elements in .jmx files that current JMeter removed, hides or discourages,
# or that JMeter 6.0 plans to remove or change. Usage: jmx-legacy-scan.sh plan.jmx...
set -u
rules='testclass="BSF|BSF element: deprecated in 3.1, hidden from menus; use JSR223 + Groovy
testclass="BeanShell|BeanShell element: discouraged; use JSR223 + Groovy
testclass="SoapSampler"|SOAP/XML-RPC Request: removed in 3.2, loads as an empty element; use HTTP Request
testclass="WebServiceSampler"|WebService(SOAP) Request: removed in 3.0; use HTTP Request
testclass="HTTPSampler2"|HttpClient 3.1 sampler: removed in 3.2; use HTTP Request (HttpClient4)
>HttpClient3.1<|HttpClient3.1 implementation: removed in 3.2; leave the implementation empty or HttpClient4
guiclass="MonitorHealthVisualizer"|Monitor Results listener: removed in 3.2; use Backend Listener + server metrics
testclass="WorkBench"|WorkBench: dropped in 4.0; use a Test Fragment or the Recording template
testclass="Mongo|MongoDB element: deprecated in 3.0, removal planned for 6.0; use JSR223 + MongoDB driver
testclass="com.atlantbh.jmeter.plugins.jsonutils|jp@gc JSON plugin: deprecated; use core JSON Extractor / JSON Assertion
testclass="kg.apc.jmeter.threads.SteppingThreadGroup"|Stepping Thread Group: use the Concurrency Thread Group
testclass="kg.apc.jmeter.perfmon.PerfMonCollector"|PerfMon: use Backend Listener + Prometheus/Grafana
com.mysql.jdbc.Driver|old MySQL driver class: 6.0 references com.mysql.cj.jdbc.Driver'
status=0
for plan in "$@"; do
while IFS='|' read -r pattern advice; do
grep -n -F -- "$pattern" "$plan" | while IFS=: read -r line _; do
printf '%s:%s: %s\n' "$plan" "$line" "$advice"
done
grep -q -F -- "$pattern" "$plan" && status=1
done <<< "$rules"
done
exit "$status"
Run against four book-era Bookshelf plans:
./jmx-legacy-scan.sh legacy-*.jmx; echo "exit=$?"
legacy-jpgc.jmx:26: jp@gc JSON plugin: deprecated; use core JSON Extractor / JSON Assertion
legacy-misc.jmx:12: WorkBench: dropped in 4.0; use a Test Fragment or the Recording template
legacy-misc.jmx:8: MongoDB element: deprecated in 3.0, removal planned for 6.0; use JSR223 + MongoDB driver
legacy-misc.jmx:6: Stepping Thread Group: use the Concurrency Thread Group
legacy-scripting.jmx:33: BSF element: deprecated in 3.1, hidden from menus; use JSR223 + Groovy
legacy-scripting.jmx:26: BeanShell element: discouraged; use JSR223 + Groovy
legacy-soap.jmx:20: SOAP/XML-RPC Request: removed in 3.2, loads as an empty element; use HTTP Request
exit=1
The class names come from bin/saveservice.properties and bin/upgrade.properties of 5.6.3 and, for the plugin
elements, from the markerClass and componentClasses of their entries in the jmeter-plugins.org catalogue. Extend the
list with the classes of any other plugin a plan uses.
Step 2: open, fix and re-save in 5.6.3
-
Install the plugins the plan needs first, with Options → Plugins Manager or with
PluginsManagerCMD.sh install-for-jmx plan.jmx, so the plan can load at all (see Plugins & Plugins Manager). -
Open the plan with File → Open. A WorkBench is converted on load: the recorder moves under the Test Plan and other content into Workbench Test Fragment. Delete what is no longer needed.
-
Replace each element reported by the scan, using the table above. The scripting case is the most common; it is shown next.
-
Run Validate on each thread group (right-click the Thread Group) to execute one iteration with one thread and no pauses, and check the results in a View Results Tree that you disable again afterwards.
-
File → Save writes the plan in the 5.6.3 format (
jmeter="5.6.3"in the root element). Commit the result so the diff shows exactly what changed.
The book-era BSF PostProcessor, as saved by 2.x/3.0:
<BSFPostProcessor guiclass="TestBeanGUI" testclass="BSFPostProcessor" testname="BSF: count">
<stringProp name="filename"></stringProp>
<stringProp name="parameters"></stringProp>
<stringProp name="script">vars.put("legacyBsf", "ok")</stringProp>
<stringProp name="scriptLanguage">groovy</stringProp>
</BSFPostProcessor>
<hashTree/>
Its replacement, added with Add → Post Processors → JSR223 PostProcessor and a core JSON Extractor in place of the
jp@gc plugin. The JSR223 Sampler only stands in for the Bookshelf POST /api/auth/login so that the fragment runs
without a server:
<JSR223Sampler guiclass="TestBeanGUI" testclass="JSR223Sampler" testname="Login (offline stub)">
<stringProp name="scriptLanguage">groovy</stringProp>
<stringProp name="parameters"></stringProp>
<stringProp name="filename"></stringProp>
<stringProp name="cacheKey">true</stringProp>
<stringProp name="script">SampleResult.setResponseData('{"token":"placeholder-token"}', 'UTF-8')
SampleResult.setDataType(org.apache.jmeter.samplers.SampleResult.TEXT)</stringProp>
</JSR223Sampler>
<hashTree>
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="Extract token">
<stringProp name="JSONPostProcessor.referenceNames">token</stringProp>
<stringProp name="JSONPostProcessor.jsonPathExprs">$.token</stringProp>
<stringProp name="JSONPostProcessor.match_numbers">1</stringProp>
<stringProp name="JSONPostProcessor.defaultValues">TOKEN_NOT_FOUND</stringProp>
</JSONPostProcessor>
<hashTree/>
<JSR223PostProcessor guiclass="TestBeanGUI" testclass="JSR223PostProcessor" testname="Count logins">
<stringProp name="scriptLanguage">groovy</stringProp>
<stringProp name="parameters"></stringProp>
<stringProp name="filename"></stringProp>
<stringProp name="cacheKey">true</stringProp>
<stringProp name="script">vars.put('loginOk', String.valueOf(vars.get('token') != 'TOKEN_NOT_FOUND'))
log.info('loginOk=' + vars.get('loginOk'))</stringProp>
</JSR223PostProcessor>
<hashTree/>
</hashTree>
Inside a Thread Group with one thread and one loop, the migrated plan runs cleanly and the scan reports nothing:
bin/jmeter -n -t migrated-scripting.jmx -l migrated.jtl -j migrated.log
grep loginOk migrated.log
./jmx-legacy-scan.sh migrated-scripting.jmx; echo "scan exit=$?"
Created the tree successfully using migrated-scripting.jmx
summary = 1 in 00:00:01 = 1.3/s Avg: 623 Min: 623 Max: 623 Err: 0 (0.00%)
... end of run
2026-10-14 13:31:14,737 INFO o.a.j.e.J.Count logins: loginOk=true
scan exit=0
The 623 ms of the single sample includes initialising the Groovy engine and compiling the script on first use; with Cache compiled script if available ticked, later iterations reuse the compiled script. That cost is why the best-practices page recommends JSR223 with Groovy over BeanShell and why the books' interpreted scripts are the first thing to replace in a plan that runs many iterations.
Step 3: align the toolchain
-
Java. Run 5.6.3 on Java 17 or 21. That is also what 6.0 will need, so the upgrade does not change the runtime twice.
-
Every node, same versions. Distributed runs need the same JMeter, Java and plugin versions on the controller and every worker.
-
Maven builds. jmeter-maven-plugin 3.8.0 defaults to JMeter 5.6.2 (its changelog: "Default to JMeter 5.6.2"), so pin the version explicitly:
<plugin>
<groupId>com.lazerycode.jmeter</groupId>
<artifactId>jmeter-maven-plugin</artifactId>
<version>3.8.0</version>
<executions>
<execution>
<id>configuration</id>
<goals>
<goal>configure</goal>
</goals>
</execution>
<execution>
<id>jmeter-tests</id>
<goals>
<goal>jmeter</goal>
</goals>
</execution>
<execution>
<id>jmeter-check-results</id>
<goals>
<goal>results</goal>
</goals>
</execution>
</executions>
<configuration>
<jmeterVersion>5.6.3</jmeterVersion>
</configuration>
</plugin>
Step 4: re-baseline
A migrated plan is a new measuring instrument. Before comparing it with any old result, run the Bookshelf baseline profile on 5.6.3 and keep it as the new reference:
bin/jmeter -n -t bookshelf-load.jmx -Jthreads=50 -Jrampup=60 -Jduration=660 \
-l baseline-5.6.3.jtl -e -o baseline-5.6.3-report
With 50 threads, a 60 s ramp-up and a 660 s duration, the hold at full load lasts 10 minutes. With the Bookshelf think time of 3 s and a typical response time of 0.2 s, each thread completes one request every 3.2 s, about 0.31 requests per second, so the plan settles near 50 / 3.2 ≈ 15.6 requests per second. If the migrated plan lands far from that number against the same build of the API, look for an element that no longer does what it did (a missing timer, a script that no longer runs) before blaming the server. Even a correct migration changes some numbers on purpose: since 5.0 HTTP state is reset on each thread-group iteration unless Same user on each iteration is ticked, and since 3.1 transaction samples are excluded from the summariser and empty ones from the dashboard.
Preparing for 6.0
None of the following needs to wait for the release. Each item can be checked on 5.6.3 today, so that the upgrade becomes a version bump plus a re-run.
| Planned change | What can break | What to do on 5.6.3 now |
|---|---|---|
Java 17 minimum |
Generators, CI images and Docker images still on Java 8 or 11. |
Move every node to Java 17 or 21 now; 5.6.3 runs on both. |
MongoDB elements removed (PR 6573) |
Plans with a MongoDB Script sampler or MongoDB Source Config no longer load. |
Run the inventory script; rewrite those steps as a JSR223 Sampler with a current MongoDB driver in |
Expired cookies no longer sent (issue 6428) |
Long soak tests whose session cookie expires mid-run start failing with authentication or session errors. |
Check the cookie lifetimes of the system under test against the test duration; add a re-login path (for Bookshelf,
repeat |
307 and 308 keep the method (issue 6080) |
A |
Find redirects in the responses (View Results Tree during Validate, or the response codes in the JTL) and decide whether the test should follow them. |
No automatic |
A server that relied on the |
Check multipart uploads against the server; set the header explicitly if it needs one. |
Open Model and Precise Throughput Timer delays from the Thread Group start (issue 6352) |
Schedules of thread groups that start after the test starts. |
See the worked example below; avoid workarounds you will have to remove. |
|
Plans and templates that still name |
Use |
Groovy 5.1.3 |
Groovy 3 scripts that use APIs removed in Groovy 4 or 5, such as |
Use |
json-path 3.0.0, Saxon-HE 13, Tika 4.x, Rhino 1.9.1, Neo4j driver 6.x |
Edge cases in JSONPath and XPath expressions, Document (text) assertions, JavaScript conditions, Bolt requests. |
Keep a functional smoke plan with assertions on extracted values, to run on 6.0 before any load test. |
Numeric properties trimmed |
Nothing should break; the change log says the trimming is there "so accidental spaces do not silently change configuration values". |
Keep property values clean anyway, so that runs behave the same on 5.6.3 and 6.0. |
Plugins |
Plugins compiled against the old libraries, or bundling their own copies, may fail; Kotlin 1.9 or later is required. |
Pin plugin versions (Plugins Manager or |
Worked example: the Open Model timing change
Bookshelf seeds its test data in a setUp Thread Group that takes about 30 s, then an Open Model Thread Group runs the
schedule rate(20/sec) random_arrivals(10 min).
-
On 5.6.3 arrival times are offsets from the start of the test. When the Open Model Thread Group starts at 30 s, the arrivals planned for the first 30 s are already overdue and are released at once: 20 arrivals per second × 30 s ≈ 600 iterations in a burst, then the schedule continues at 20 per second. The burst is not a property of the system under test, and it distorts the first minute of the dashboard.
-
The 5.6.3 workaround is to start the schedule with a pause that covers the setUp phase:
pause(30 sec) rate(20/sec) random_arrivals(10 min). -
On 6.0 (planned) delays are measured from the start of the Thread Group, so the burst disappears without a workaround, and the same workaround then delays the real load by an extra 30 s. Remove the leading pause when upgrading, and keep the schedule in a property (
${__P(schedule,...)}) so that it is changed in one place.
Related tools that changed too
-
JMeter Plugins Manager: version 2.0 is the one this section uses;
cmdrunner2.3 for the command-line installer. The catalogue at jmeter-plugins.org is a community project, not part of Apache JMeter. -
gRPC Request plugin: the original
zalopay-oss/jmeter-grpc-requestrepository was archived in April 2024 after 1.2.6; the catalogue now points to the bakthava continuation (2.0.0 to 2.0.2, 2026, with mTLS and Java 21 support). It supports unary calls only. See gRPC Load Testing. -
Programmatic plans: the experimental Kotlin and Java DSL in core 5.6 is different from JMeter Java DSL 2.3, a third-party library from Abstracta. Both are covered later in this section, in the programmatic test plans page.
-
Docker and Gradle: there is still no official Apache JMeter Docker image and no official Gradle plugin; book recipes based on Vagrant, Flood.io or specific cloud images are dated.
Pitfalls when upgrading
-
Trusting the exit code. JMeter exits with 0 even when a converted element produced no samples or every sample failed (see Running Tests in CLI Mode); check the sample count and the error rate in
statistics.jsonor the JTL. -
Comparing across versions without a new baseline. Changes such as the 5.0 HTTP state reset or the 3.1 transaction handling in reports alter numbers by design.
-
Mixing versions in a distributed run. The controller and the workers must run the same JMeter, Java and plugins.
-
Keeping an old copy of Groovy. Since 3.0 Groovy is bundled in
lib; a copy insearch_pathsoruser.classpathleft over from a 2.x setup conflicts with it. -
Editing
jmeter.propertiesto restore old behaviour. Put overrides inuser.propertiesso that the next upgrade does not discard them (see Installation & Configuration). -
Treating master-branch behaviour as released. Anything described as 6.0 on this page comes from the development branch and may still change.
References
-
Bayo Erinle, JMeter Cookbook, Packt, 2014: ch. 1, 2, 4, 5, 6, 7, 8 and the appendix (JMeter 2.11)
-
Bayo Erinle, Performance Testing with JMeter, 2nd ed., Packt, 2015: ch. 2, 3, 5 and 7 (JMeter 2.12)
-
Sai Matam and Jagdeep Jain, Pro Apache JMeter, Apress, 2017: ch. 3, 4, 5, 6, 7 and 9 (JMeter 3.0)