CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/jmeter-load-testing

Authors Apache JMeter `.jmx` test plans (Thread Groups + HTTP samplers + assertions + listeners) in the JMeter GUI, runs them headlessly via `jmeter -n -t plan.jmx -l results.jtl`, generates an HTML dashboard with `-e -o`, and gates CI on JTL parsing. Use when the project has an existing JMeter investment, needs JVM-native load tooling, or works in domains with strong JMeter community support (banking, telecom, enterprise).

80

Quality

100%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

High

Do not use without reviewing

Overview
Quality
Evals
Security
Files
name:
jmeter-load-testing
description:
Authors Apache JMeter `.jmx` test plans (Thread Groups + HTTP samplers + assertions + listeners) in the JMeter GUI, runs them headlessly via `jmeter -n -t plan.jmx -l results.jtl`, generates an HTML dashboard with `-e -o`, and gates CI on JTL parsing. Use when the project has an existing JMeter investment, needs JVM-native load tooling, or works in domains with strong JMeter community support (banking, telecom, enterprise).

jmeter-load-testing

Overview

Apache JMeter is the long-running JVM-native load-testing tool. Tests are XML .jmx files authored in JMeter's GUI; CI runs them headless via the jmeter CLI (jmeter-getstarted).

The official guidance is explicit:

"GUI mode should only be used for creating the test script, CLI mode (NON GUI) must be used for load testing." (jmeter-getstarted)

This skill covers the CLI / CI side. Authoring is GUI-driven and out of scope here - see the JMeter user manual for the Thread Group / HTTP Sampler / Assertion authoring flow.

When to use

  • The project already has .jmx test plans.
  • The team is on the JVM and prefers JMeter's mature ecosystem (BlazeMeter, Taurus, plugin manager, distributed mode).
  • A specific protocol is needed that JMeter has first-class support for: JDBC, JMS, MQTT, FTP, LDAP, SOAP - k6's plugin landscape is weaker for niche protocols.

If the team is starting fresh, evaluate k6-load-testing (developer-friendly JS), gatling-load-testing (JVM DSL), or locust-load-testing (Python) before adopting JMeter - XML authoring has a steep learning curve.

Install

JMeter requires Java 8 or higher with JAVA_HOME set. Download the latest release from jmeter.apache.org and extract - there is no installer (jmeter-getstarted).

For Docker-based CI, official images are at apache/jmeter. Pin to a specific tag rather than latest.

Running

Canonical CLI invocation

Per jmeter-getstarted:

jmeter -n -t test.jmx -l results.jtl
FlagPurpose
-nNon-GUI mode. Required for load tests.
-tPath to the .jmx test plan.
-lOutput file for raw sample results (JTL - CSV-shaped).

With HTML dashboard

Per jmeter-getstarted:

jmeter -n -t test.jmx -l results.jtl -e -o report_folder
FlagPurpose
-eGenerate the HTML dashboard report automatically.
-oOutput folder (must be empty or non-existent).

The dashboard shows percentiles, throughput, error rates, response- time graphs, and per-sampler breakdowns - the canonical JMeter output for human review.

Other useful flags

FlagPurpose
-J<property>=<value>Override a JMeter property at the JVM level.
-G<property>=<value>Override a property in distributed (remote) mode.
-Jjmeter.save.saveservice.output_format=csvForce CSV JTL (vs. XML).
-q <props-file>Additional properties file.
-rStart the test on remote slaves (distributed mode).
-XExit JMeter when the test finishes.

For multi-environment runs, parameterize the test plan with ${__P(api.base.url, default)} and override at the CLI:

jmeter -n -t orders.jmx -l results.jtl \
  -Japi.base.url=https://staging.example.com \
  -Japi.token=$API_TOKEN

Parsing results

The JTL file is the structured artifact for CI gating. Default JTL columns (CSV): timeStamp, elapsed, label, responseCode, responseMessage, threadName, dataType, success, failureMessage, bytes, sentBytes, grpThreads, allThreads, URL, Latency, IdleTime, Connect.

Quick-and-dirty pass/fail with awk:

# Count errors
awk -F',' 'NR>1 && $8=="false"' results.jtl | wc -l

# Compute mean response time
awk -F',' 'NR>1 { sum+=$2; n++ } END { print sum/n }' results.jtl

For richer parsing, use the JMeter HTML report's statistics.json under the report folder - it contains the percentiles per sampler in JSON form.

CI integration

# .github/workflows/jmeter.yml
name: load-test

on:
  pull_request:
    paths: ['tests/load/**.jmx']
  schedule:
    - cron: '0 4 * * *'

jobs:
  jmeter:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5

      - name: Run JMeter via Docker
        env:
          API_TOKEN: ${{ secrets.STAGING_API_TOKEN }}
        run: |
          docker run --rm \
            -v "$PWD:/work" \
            -w /work \
            apache/jmeter \
              -n -t tests/load/orders.jmx \
              -l results.jtl \
              -e -o report \
              -Japi.token=$API_TOKEN \
              -Japi.base.url=https://staging.example.com

      - name: Pass/fail gate
        run: |
          ERRORS=$(awk -F',' 'NR>1 && $8=="false"' results.jtl | wc -l)
          if [ "$ERRORS" -gt 10 ]; then
            echo "::error::Got $ERRORS errors (>10 threshold)"
            exit 1
          fi

      - name: Upload report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: jmeter-report
          path: |
            report/
            results.jtl
          retention-days: 14

The Docker invocation pattern keeps the CI runner clean - no Java / JMeter install on the runner.

Anti-patterns

Anti-patternWhy it failsFix
Running tests in GUI mode "just for this one quick run"GUI runner adds overhead; metrics are skewed; per jmeter-getstarted this is explicitly forbidden for load tests.Always -n. GUI is for authoring only.
Hard-coding URLs / tokens in the .jmx XMLTest plan binds to one environment.Parameterize: ${__P(api.base.url, ...)}; override with -J.
Saving JTL in XML formatXML JTL files are 5-10x larger than CSV; slow to parse.Force CSV with -Jjmeter.save.saveservice.output_format=csv.
Listeners enabled in CI runsUI listeners (View Results Tree, Aggregate Report) consume RAM proportional to sample count; OOMs at scale.Disable all listeners in .jmx; emit JTL only; generate HTML report post-run via -e -o.
One mega-test-plan with 100 samplersFailure attribution is hard; runtime dominated by one slow endpoint.Split into per-domain .jmx files; run as separate CI jobs.
Threshold gates only on error rateA 30-second response that succeeds passes the rate gate but breaks UX.Pair error-rate with percentile gates parsed from statistics.json.

Limitations

  • XML authoring. .jmx files are not human-friendly; reviews of test-plan changes are awkward.
  • Memory hungry. JMeter's per-sample memory overhead is high vs. k6 / Gatling.
  • Single-machine VU limits. ~1000 threads per machine before JVM contention; for higher loads, use distributed mode (master + remote slaves) or move to a tool with a smaller per-VU footprint.
  • Plugin ecosystem fragmentation. Many JMeter plugins are abandoned; vet plugin maintenance status before depending on one.

References

  • jmeter-getstarted - canonical CLI flags, GUI-vs-CLI guidance, dashboard generation.
  • Apache JMeter user manual - https://jmeter.apache.org/usermanual/
  • k6-load-testing, gatling-load-testing, locust-load-testing - alternatives by stack.
  • perf-budget-gate - downstream gate aggregating multiple runner verdicts.
Workspace
testland
Visibility
Public
Created
Last updated
Publish Source
GitHub
Badge
testland/jmeter-load-testing badge