On this page9 sections
CommandsIntermediate7-9 min reference

JMeter

A practical reference for Apache JMeter — the components you'll wire together, the assertions you'll write, and the CLI flags you'll reach for in CI.

Thread Groups

The Thread Group sets concurrency, ramp-up, and iteration count. Every test plan starts with at least one.

Standard Thread Group

Number of Threads (users): 100
Ramp-Up Period (seconds):  60     # 100 users started over 60s
Loop Count:                10     # each user runs the test 10 times
                                  # — or check "Forever" and use a Duration timer
Duration (seconds):        300    # cap the run at 5 minutes
Startup delay (seconds):   0

Concurrent users at any moment: Threads × (1 - elapsed_time / ramp_up) while ramping, then full Threads.

Stepping Thread Group (jp@gc plugin)

Gradual load increase, useful for finding breaking points.

Threads:        1000
Initial delay:  0s
Start:          0 threads
Increment:      50 threads every 30s, hold 5s between
Hold:           300s at peak
Shutdown:       50 threads every 10s

Ultimate Thread Group (jp@gc plugin)

Multi-row schedule for complex load patterns.

Row 1: 50 threads, 30s startup, 60s hold,  30s shutdown
Row 2: 50 threads, 60s startup, 120s hold, 30s shutdown

Combines into a layered ramp profile.

setUp and tearDown Thread Groups

Run before/after the main test plan — ideal for one-time DB seeding or cleanup. Threads here don't count toward main load.

Quick concurrency math

Concurrent users  = Throughput (req/sec) × Avg Response Time (sec) / Pacing
Throughput target = Users × Iterations / Total Run Time

Samplers

Samplers issue the actual requests.

HTTP Request

Method:    GET
Server:    api.example.com
Port:      443
Protocol:  https
Path:      /v2/users
Body data: {"name":"Ada"}     # for POST/PUT

Use ${variable} syntax to interpolate from CSV / extractors:

/v2/users/${user_id}

JDBC Request

For database load tests, pair with JDBC Connection Configuration.

SELECT id, status FROM orders
WHERE customer_id = ${customer_id}
  AND created_at > NOW() - INTERVAL '1 day';
Query Type:      Select Statement
Variable Names:  order_id, order_status
Result Variable: result

JSR223 Sampler (Groovy)

For custom logic that doesn't fit a simple HTTP/JDBC sampler.

def random = new Random()
def value = random.nextInt(1000)
vars.put("random_id", value.toString())
 
log.info("Generated id: ${value}")
SampleResult.setResponseData("id=${value}", "UTF-8")
SampleResult.setSuccessful(true)

Prefer Groovy over BeanShell — Groovy compiles once, BeanShell interprets on every iteration.

Debug Sampler

Captures the current state of all variables and properties — useful while authoring tests, disable in real load runs.

Configuration Elements

Defaults applied to all child samplers in the same scope.

HTTP Request Defaults

Server:           api.example.com
Port:             443
Protocol:         https
Path:             /v2
Connect Timeout:  5000ms
Response Timeout: 30000ms

HTTP Header Manager

Content-Type:  application/json
Accept:        application/json
Authorization: Bearer ${auth_token}
X-Request-ID:  ${__UUID()}

Drop in once per Thread Group. Handles Set-Cookie automatically across requests, including session cookies.

CSV Data Set Config

Filename:           users.csv
Variable Names:     username,password,email
Recycle on EOF:     True
Stop thread on EOF: False
Sharing mode:       All threads

users.csv:

ada,secret1,ada@example.com
bob,secret2,bob@example.com

Reference in samplers: ${username}.

User Defined Variables

base_url         https://api.example.com
api_version      v2
default_timeout  5000

Set once at plan or thread-group level — useful for environment switching.

JDBC Connection Configuration

Variable Name: ordersDB
URL:           jdbc:postgresql://db.internal:5432/orders
Driver class:  org.postgresql.Driver
Username:      ${db_user}
Password:      ${db_pass}
Pool:          10 connections

Assertions

Validate response correctness, not just availability.

Response Assertion

Apply to:                 Main sample only
Field to test:            Response Body  (or Response Code, Headers, URL)
Pattern matching rules:   Contains       (or Matches, Equals, Substring)
Pattern:                  "status":\s*"ok"

JSON Assertion

JSON Path:        $.user.email
Expected Value:   ada@example.com
Match as regex:   false
Invert assertion: false

Duration Assertion

Duration in milliseconds: 2000

Fails samplers that take longer than 2 seconds.

Size Assertion

Size in bytes:      1048576
Type of comparison: less than

XPath Assertion

For XML/HTML responses.

//user[@id='${user_id}']/email

Pre/Post Processors

JSR223 PreProcessor (Groovy)

Generate dynamic data before the sampler runs.

import java.security.MessageDigest
 
def ts = System.currentTimeMillis().toString()
def secret = vars.get("api_secret")
def payload = ts + vars.get("user_id")
def digest = MessageDigest.getInstance("SHA-256")
def hash = digest.digest((payload + secret).bytes).encodeHex().toString()
 
vars.put("timestamp", ts)
vars.put("signature", hash)

JSON Extractor

Capture values from JSON responses for use in subsequent requests.

Names of created variables: auth_token
JSON Path expressions:      $.access_token
Match No.:                  1     # 0 = random, -1 = all matches
Default Values:             NOT_FOUND

Then ${auth_token} in later samplers.

Regular Expression Extractor

For correlating non-JSON responses (HTML, plain text).

Names of created variables: csrf
Regular Expression:         name="csrf_token" value="([^"]+)"
Template:                   $1$
Match No.:                  1
Default Value:              NOT_FOUND

CSS/JQuery Extractor

Reference Name: page_title
CSS Selector:   h1.page-title
Attribute:      (leave blank for text)
Match No.:      1

XPath Extractor

Reference Name: order_id
XPath Query:    //order[1]/@id

Listeners

Disable all listeners during real load tests — they consume memory and skew results. Run with the -l CLI flag instead and analyse offline.

View Results Tree

Per-request request/response detail. Author and debug only.

Summary Report

Aggregate stats per sampler — count, average, min/max, error %, throughput, KB/s. The cheapest listener for live runs.

Aggregate Report

Adds percentiles (50 / 90 / 95 / 99) — what most performance reviews actually care about.

Backend Listener (InfluxDB / Graphite)

Stream metrics to a time-series DB during the run for live Grafana dashboards.

Backend Listener implementation: InfluxdbBackendListenerClient
influxdbUrl:                     http://influx.internal:8086/write?db=jmeter
application:                     my-api
measurement:                     jmeter

Simple Data Writer

Write raw samples to a .jtl file — configurable to JSON, CSV, or XML.

Timers

Insert pauses to model real user think-time and avoid hammering the target.

Constant Timer

Thread Delay (ms): 1000

Gaussian Random Timer

Deviation (ms):   500
Constant Delay:   1000

Delays distribute around 1000ms ± 500.

Uniform Random Timer

Random Delay Maximum (ms): 2000
Constant Delay Offset:     500

Delay is 500 + rand(0, 2000).

Constant Throughput Timer

Caps a thread group to a target rate regardless of response time.

Target throughput (samples/min): 600     # 10 req/sec
Calculate Throughput based on:   all active threads in current thread group

CLI Mode (Non-GUI)

GUI mode is for authoring only — always run real load tests headless.

Basic run

jmeter -n -t test.jmx -l results.jtl
  • -n non-GUI mode
  • -t test plan
  • -l results file (.jtl)

Generate the dashboard report

jmeter -n -t test.jmx -l results.jtl -e -o ./report
  • -e generate dashboard report at end
  • -o output folder (must not exist)

Override properties from CLI

jmeter -n -t test.jmx \
  -l results.jtl \
  -Jthreads=200 \
  -Jramp_up=120 \
  -Jduration=600 \
  -Jbase_url=https://staging.example.com

In test.jmx reference these as ${__P(threads,50)} (with default).

Generate report from existing JTL

jmeter -g results.jtl -o ./report

Distributed (master/worker) run

jmeter -n -t test.jmx -l results.jtl \
  -Rworker1.example.com,worker2.example.com \
  -X
  • -R comma-separated worker hosts
  • -X shut down workers after run

Correlation & Dynamic Data

Most real APIs require capturing dynamic values (session, CSRF, IDs) from one response and feeding them into the next.

Capture and reuse a token

  1. Add JSON Extractor under the login request:

    Variable:  auth_token
    JSON Path: $.access_token
    
  2. In the next sampler's headers (HTTP Header Manager):

    Authorization: Bearer ${auth_token}
    

CSRF token correlation

Form pages typically inline a CSRF token in HTML. Extract with Regular Expression Extractor:

Variable: csrf
Regex:    name="csrf_token" value="([^"]+)"
Template: $1$

Submit with the form post body:

csrf_token=${csrf}&username=ada&password=secret

Built-in functions

${__counter(TRUE,)}                 per-thread counter (TRUE) or global (FALSE)
${__time(yyyy-MM-dd,)}              formatted current time
${__time(/1000,)}                   Unix timestamp seconds
${__UUID()}                         v4 UUID
${__Random(1,1000)}                 random int between bounds
${__RandomString(10,abc123)}        random string from char set
${__P(propName,default)}            read JVM property (overridable via -J)
${__threadNum()}                    current thread index
${__iterationNum()}                 current iteration index
${__groovy(System.currentTimeMillis())}   inline Groovy
${__BeanShell(some.code())}         legacy, prefer __groovy

Parameterise via CSV (per-iteration data)

csv: users.csv → variables: username, password

Each thread reads one row per iteration; the request body uses ${username} / ${password} and runs through the CSV.