Properties, Variables & Functions

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.

Baseline date: 2026-10-14. This page was written against Apache JMeter 5.6.3, the latest release on that date, with Java 17 or later (21 recommended). No JMeter 6.0 release existed on that date, so any 6.0 behaviour is not described here beyond what the 5.6.3 documentation states. The load-model and plugin versions used elsewhere in this section (Plugins Manager 2.0, jmeter-maven-plugin 3.8.x, the gRPC Request plugin 2.0.x) are not needed on this page.

Almost every non-trivial test plan has values that change: the host name for each environment, the number of users, a search term picked per iteration, a token captured from one response and sent in the next, a timestamp. JMeter gives these values three vehicles: properties (global to the JVM), variables (local to one virtual user) and functions (small calls such as ${__Random(1,100)} that are evaluated where they are written). This page explains the difference between the three, how values enter a run from the command line and from files, how threads can share data, the exact syntax and escaping rules of a function call, and a catalogue of the built-in functions grouped by purpose. The examples use the Bookshelf scenario of this section.

Properties versus variables

Aspect Properties Variables

Scope

Global to the JMeter JVM: all threads and all thread groups see the same value.

Local to one thread: a thread that changes a variable changes only its own copy.

Defined in

jmeter.properties, user.properties, property files given with -q, and the command line with -J or -G. Created at run time with __setProperty.

The Test Plan or a User Defined Variables element, extractors, a CSV Data Set Config, a JSR223 element (vars.put), counters and other elements.

Read with

${__P(name,default)} or ${__property(name)}, or in a script through props.

${name} in any field that accepts it, or in a script through vars.

Main use

Configuring JMeter itself and passing run parameters (users, duration, host) into a plan.

Per-user data: ids, tokens, search terms, extracted values.

Case

Case-sensitive.

Case-sensitive.

The user manual states the rule directly: properties are global to JMeter and are mainly used to define some of the defaults JMeter uses, while variables are local to each thread. A plan can read properties but a property cannot hold a value that is specific to one thread. The Test Plan and User Defined Variables values are available at startup, and every thread receives a copy of the initial variables when it starts. A later change, for example by a Regular Expression Extractor, applies only to the thread that made it.

flowchart LR subgraph JVM[JMeter JVM] P[(Properties: global)] subgraph T1[Thread 1] V1[(Variables)] end subgraph T2[Thread 2] V2[(Variables)] end end CLI[-J / -G / user.properties / -q file] --> P UDV[Test Plan and User Defined Variables] -->|copy at thread start| V1 UDV -->|copy at thread start| V2 P -->|P and property functions| V1 P -->|P and property functions| V2 V1 -->|setProperty| P

Where values come from

Source Effect

Test Plan element, User Defined Variables table

Name and value pairs available to every thread from the start. Values may use functions and other variables.

User Defined Variables configuration element

Same table, as a separate element. Wherever it is placed, every User Defined Variables element is processed once at the start of the test, in tree order, not when the thread reaches its position.

Properties

Read with __P or __property, then usually fed into a field or a variable.

CSV Data Set Config, extractors, User Parameters, JSR223 elements

Write per-thread variables during the test (covered in later pages on test data, correlation and scripting).

Two behaviours matter when mixing them. A user-defined variable whose name equals a built-in function name overrides that function. And an undefined variable or function reference is not an error: the text is returned unchanged and nothing is logged, so a typo such as ${usr} appears literally in the request. Check the sampler’s request in a View Results Tree listener during validation.

Passing values from the command line

A plan becomes reusable when its sizing is read from properties. The user manual defines the relevant options as follows.

Option Meaning (user manual wording)

-J name=value (--jmeterproperty)

Defines a local JMeter property, an additional JMeter property for this JVM.

-G name=value (--globalproperty)

Defines a JMeter property to be sent to all remote servers (used in distributed runs).

-D name=value (--systemproperty)

Defines a Java system property value.

-p file (--propfile)

The JMeter property file to use.

-q file (--addprop)

Additional JMeter property file(s).

-S file (--systemPropertyFile)

Additional system property file(s).

-L category=level

Overrides a logging level (for example -Ljmeter.engine=DEBUG).

Property loading follows a fixed order: the initial property file (jmeter.properties, or the -p file), then logging initialisation, then user.properties, then system.properties, and finally the remaining command-line options. A later source overrides an earlier one, so -J wins over a file. The manual recommends editing user.properties in the bin directory, or keeping your own copy of jmeter.properties passed with -p, rather than editing the shipped jmeter.properties in place. Property changes take effect only after JMeter restarts.

A parameterised plan

Create a Thread Group (Add → Threads (Users) → Thread Group) and, in its fields, type function calls instead of numbers. The fragment below is a Bookshelf Thread Group whose size, ramp-up and duration come from properties, with defaults suitable for a smoke run:

<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Bookshelf users" enabled="true">
  <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
  <elementProp name="ThreadGroup.main_controller" elementType="LoopController"
               guiclass="LoopControlPanel" testclass="LoopController">
    <boolProp name="LoopController.continue_forever">false</boolProp>
    <intProp name="LoopController.loops">-1</intProp>
  </elementProp>
  <stringProp name="ThreadGroup.num_threads">${__P(threads,1)}</stringProp>
  <stringProp name="ThreadGroup.ramp_time">${__P(rampup,1)}</stringProp>
  <boolProp name="ThreadGroup.scheduler">true</boolProp>
  <stringProp name="ThreadGroup.duration">${__P(duration,60)}</stringProp>
</ThreadGroup>

Then run it in CLI mode, overriding the defaults for the section’s load profile of 50 users, a 60 second ramp-up and a 10-minute hold (the scheduler duration includes the ramp-up, so it is 60 + 600 = 660 s):

jmeter -n -t bookshelf-load.jmx -l load.jtl -Jthreads=50 -Jrampup=60 -Jduration=660 -Jhost=localhost

With no overrides the same plan runs one user for 60 seconds. ${__P(threads)} with no default returns 1, the function’s documented default, which makes a forgotten -J produce a smoke test instead of a failure.

A properties file avoids long command lines and can be committed per environment. Create staging.properties:

host=bookshelf.staging.example
threads=20
rampup=30
duration=300

and pass it with -q:

jmeter -n -t bookshelf-load.jmx -q staging.properties -l staging.jtl

Both are processed after user.properties and in the order they appear on the command line, so with -q written before -J a command such as jmeter -n -t bookshelf-load.jmx -q staging.properties -Jthreads=5 keeps the file’s other values and overrides only threads. Remember that load is only ever aimed at localhost or systems you own; the host above is a placeholder.

The -J and -G distinction

-J defines a property in the local JVM. In a distributed run the controller does not forward it, so remote servers do not see it. -G defines a property that is sent to all remote servers, and a -G property file is also accepted (for example jmeter -n -t testplan.jmx -r -Gprop=val -Gglobal.properties). Use -G for anything a function on a load generator must read, such as threads, and -J for controller-only values. The distributed testing page of this section covers the topology.

Properties in 2.x/3.0 books versus 5.6

The 2.x and 3.0 era books show the same -J and __P mechanism, but older examples often read properties through __javaScript or __BeanShell calls. Current JMeter documentation steers away from both (see the scripting group below) and Groovy has been the default language of the JSR223 elements since 3.1. JMeter 5.5 also changed the time functions to use DateTimeFormatter (see below).

Sharing data between threads

Variables are per thread, so a value that every thread must see is stored in a property. The function __setProperty defines a property global to the test plan, and the manual states that such properties can be used to pass information between threads.

<!-- In a setUp Thread Group: publish the admin token once -->
<JSR223PostProcessor guiclass="TestBeanGUI" testclass="JSR223PostProcessor" testname="Publish token">
  <stringProp name="scriptLanguage">groovy</stringProp>
  <stringProp name="script">props.put('adminToken', vars.get('token'))</stringProp>
</JSR223PostProcessor>

<!-- In a worker thread group: read it back as a header value -->
<stringProp name="Header.value">Bearer ${__P(adminToken)}</stringProp>

The same effect is possible without a script by calling the function in a field, for example the Value of a User Defined Variables row: ${__setProperty(adminToken,${token})}. The function returns an empty string, or the previous value when its third argument is true. Three rules keep the pattern safe:

  • Ordering. A property read by __P is read when the field is evaluated. Publish it in a setUp Thread Group, which runs before the regular thread groups, or the readers see the default.

  • Race conditions. Two threads writing the same property race. Write it once and read it often.

  • Cost. Properties are one shared map, and a script that stores large objects there keeps them alive for the whole test.

Function syntax and escaping

A function call has the form ${__functionName(arg1,arg2,...)}. Functions with no arguments may omit the parentheses, as in ${__threadNum}. The page states these rules:

Rule Detail

Commas

Arguments are separated by commas. A comma that belongs to an argument must be escaped with a backslash, \,. An unescaped comma splits the parameter, which for scripts typically causes a script error.

Backslashes

In a string that contains a function or variable reference, a backslash before $, , or \ is removed.

Names

Function and variable names are case-sensitive. JMeter trims spaces from variable names.

Undefined names

The reference is returned unchanged, with no error logged.

Nesting

A variable name cannot be nested directly. ${A${N}} does not work; use ${__V(A${N})}.

Where a function may run

Thread-dependent functions such as __threadNum do not work at Test Plan level, nor do __split, __regexFunction and the variable-evaluation functions, because there is no thread yet. Configuration elements run in a separate thread, so __threadNum does not work properly in them.

Output variable

Most functions take a trailing optional variable name; the result is then also stored as ${name}.

Nested references with __V, __eval and __evalVar

Three functions solve the no-nesting rule:

  • __V evaluates a variable whose name is itself built dynamically. If N is 3, ${__V(book${N})} returns the value of book3. A second argument is a default.

  • __eval evaluates a string, interpolating the variables and functions inside it. It is the way to expand a value that was loaded as text, for example a CSV cell that itself contains ${__UUID()}.

  • __evalVar evaluates the expression stored in a variable.

# book1=978-0-00-000001-0   book2=978-0-00-000002-7   N=2
${__V(book${N})}            -> 978-0-00-000002-7
# template=ISBN ${book1}
${__eval(${template})}      -> ISBN 978-0-00-000001-0
${__evalVar(template)}      -> ISBN 978-0-00-000001-0

Escaping a script

Commas inside a __groovy call must be escaped, and the manual’s own example is ${__groovy(vars.get("myVar").substring(0\,2))}. For anything longer, store the script in a variable (a User Defined Variables row) and reference it, which avoids the escapes. Also avoid placing variable values inside the script text: a changing script cannot be cached, so read values through vars instead (see the scripting group below).

The Function Helper dialog

Open it from the Tools menu (Tools → Function Helper Dialog). Choose a function in the Choose a function list, fill in the parameter table, and press Generate; the generated call, for example ${__Random(1,100,)}, can be copied into a field. The dialog also shows the result of the last evaluation, and its parameter table lists each argument with a short description. It does not escape values for you: a comma inside a parameter value must still be typed as \,.

Function catalogue

Every function name below was checked against the official functions reference on 2026-10-14. In every call the variable name argument is optional unless marked required.

Random

Function Arguments Notes and example

__Random

Minimum (required), maximum (required), variable name.

A random integer in the range. ${__Random(1,100)} or ${__Random(0,10,MYVAR)}.

__RandomString

Length (required), characters to use, variable name.

${__RandomString(10,abcdefg)} returns ten characters drawn from the given set.

__RandomDate

Format (default yyyy-MM-dd), start date (default now), end date (required), locale, variable name.

${__RandomDate(,,2050-07-08,,)} returns a date between now and 2050-07-08.

__RandomFromMultipleVars

Variables separated by |, variable name.

Picks one value from several variables.

__UUID

None.

A pseudo-random type 4 UUID, ${__UUID()}. Useful for unique ids such as a loan reference.

Counters and thread information

Function Arguments Notes and example

__counter

Per-user flag TRUE or FALSE (required), reference name.

Starts at 1 and increments by 1; the maximum is 2,147,483,647. TRUE gives each thread its own counter, FALSE a single global counter. Several calls in the same iteration do not increment it again.

__threadNum

None.

The current thread number, for example to build a unique user name.

__threadGroupName

None.

The name of the running thread group.

__intSum and __longSum

First value, second value, optional further values, reference name last.

Integer and long addition.

Time

Function Arguments Notes and example

__time

Format, variable name.

No format returns milliseconds since the epoch. /1000 divides it, giving seconds. Aliases YMD (yyyyMMdd), HMS (HHmmss), YMDHMS (yyyyMMdd-HHmmss), USER1 and USER2 (from the time.USER1 and time.USER2 properties). ${__time(YMD,)} returns 20180121 on 21 January 2018.

__timeShift

Format, date to shift (default now), duration, locale, variable name.

ISO-style durations such as PT20.345S, PT15M, PT10H, P2D or -P6H3M. ${__timeShift(dd/MM/yyyy,21/01/2018,P2D,,)} returns 23/01/2018.

__dateTimeConvert

Date string (required), source format, target format (required), variable name.

Converts a date between formats.

The aliases can be redefined in properties, for example time.YMD=yyMMdd. Since JMeter 5.5 these functions use DateTimeFormatter instead of SimpleDateFormat, so format letters can differ from older plans: the manual notes that u now means year, not day-of-week number. Plans written against 2.x or 3.0 books that use SimpleDateFormat patterns need a check.

Files

Function Arguments Notes

__CSVRead

File name (required), column number (required; next moves to the next line).

Splits lines on commas (property csvread.delimiter). The file is loaded into memory on first use and each thread has its own row pointer. File names are case-sensitive. Not suitable for large files: the manual recommends the CSV Data Set Config element instead.

__StringFromFile

File name (required), variable name (default StringFromFile_), start and end sequence numbers.

Each call reads the next line, and all threads share the instance. At the end of the file it wraps, unless a loop count has been reached. Errors return **ERR**.

__FileToString

File name (required), encoding (platform default), variable name.

Reads the whole file on every call. Errors return **ERR**.

__StringToFile

Path (required), string (required), append (default true), encoding (default UTF-8).

Writes a string to an absolute path. Use \n for line breaks.

__XPath

File, XPath expression.

Returns the next match from an XML file on each call, wrapping at the end.

Prefer the CSV Data Set Config for test data. File-reading functions run for every evaluation, add disk work to the load generator and, for __FileToString, reread the entire file each time.

Scripting

Function Arguments Notes

__groovy

Expression (required), variable name.

Predefined variables: log, ctx, vars, props, threadName, sampler, prev and OUT. ${__groovy(123*456)} returns 56088. The groovy.utilities property loads a common utility script (a sample utility.groovy ships in bin).

__jexl3

Expression (required), variable name.

Commons JEXL 3, same variables as __groovy, multiple statements allowed. / and div both divide normally, so an integer result needs an explicit conversion.

__jexl2

Expression, variable name.

Commons JEXL 2, kept for older plans.

__javaScript

Expression (required), variable name.

Runs on Nashorn (Rhino with the property javascript.use_rhino=true). The manual advises __jexl3 or __groovy for high thread counts because JavaScript performs worse. JMeter is not a browser and does not interpret JavaScript in downloaded pages.

__BeanShell

Script (required), variable name.

Each occurrence gets its own interpreter, so variables persist across calls; the manual says __groovy performs better.

Avoid __javaScript and __BeanShell in new plans. A function is re-evaluated on every call on every thread, so the engine behind it sets the CPU cost per request. Groovy compiles and caches the script text, which is why the manual says not to interpolate variable values into it; with vars.get(...) the text is constant and the compiled script is reused.

# Avoid: the script text changes with the variable, so it cannot be cached
${__groovy("${myVar}".substring(0\,2))}
# Prefer: the text is constant
${__groovy(vars.get("myVar").substring(0\,2))}

Strings and encoding

Function Arguments Notes

__urlencode and __urldecode

String (required).

application/x-www-form-urlencoded, UTF-8. Encode a search term used in a query string.

__escapeHtml and __unescapeHtml

String (required).

Convert HTML entities to and from characters.

__escapeXml

String (required).

Escapes XML 1.0 entities.

__changeCase

String (required), mode (default UPPER; also LOWER, CAPITALIZE; case-insensitive), variable name.

Changes case.

__digest

Algorithm (required), string (required), salt, upper-case flag (default lower case), variable name.

MD2, MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512. ${__digest(MD5,Errare humanum est,,,)} returns c49f00b92667a35c63708933384dad52.

__split

String to split (required), variable name (required), delimiter (default comma).

Creates VAR_1, VAR_2 and so on, and VAR_n with the count. Adjacent or trailing delimiters give ?. The delimiter comma must be escaped as \,. Handy with a ForEach Controller.

__regexFunction

Regex (required), template (required, for example $1$), match number (default 1; integer, RAND, ALL or a fraction), separator for ALL, default, reference name, input variable.

A reference name refName creates ${refName}, ${refName_g0} (whole match), ${refName_g1} and so on, plus ${refName_matchNr}. Prefer extractors for correlation (a later page).

__char

Numbers.

${__char(13,10)} produces CRLF.

__unescape

String.

Processes Java escapes such as \n and \t.

__escapeOroRegexpChars

String.

Escapes ORO regular-expression meta characters.

Information, properties and logging

Function Arguments Notes

__machineName and __machineIP

Variable name.

Local host name and IP address; useful to tag which load generator produced a sample.

__samplerName

Variable name.

The current sampler’s label.

__TestPlanName

None.

The test plan’s name.

__log and __logn

String (required), level (default INFO; OUT, ERR, DEBUG, INFO, WARN, ERROR), throwable text, comment.

__log writes a message and returns its input; __logn returns an empty string. OUT and ERR always print to the console. ${__log(${VAR},,,VAR=)} logs a labelled variable.

__P

Property name (required), default (default 1).

Shorthand for a -J property; cannot store to a variable.

__property

Property name (required), variable name, default.

Returns the property, or the default; with no default and no property it returns the name.

__setProperty

Name (required), value (required), flag to return the original value.

Sets a global property; returns an empty string.

__isPropDefined and __isVarDefined

Name (required).

Return true or false.

The Bookshelf plan puts several of these together. A unique reference for each loan, an ISBN picked at random from a list and an encoded search term:

POST /api/loans   {"isbn":"${isbn}","ref":"loan-${__threadNum}-${__counter(TRUE,)}-${__UUID}"}
GET  /api/books?query=${__urlencode(${term})}&since=${__timeShift(yyyy-MM-dd,,-P7D,,)}

Load-generator cost of functions

A function in a field is evaluated every time the field is, for every thread. A __groovy call in the Path of an HTTP sampler runs once per request. At 500 requests per second that is 500 script evaluations per second; Groovy’s script cache keeps each one cheap, while __BeanShell and __javaScript cost noticeably more. The properties reference also lists function.cache.per.iteration (default false), which caches function results during one iteration; it may give unexpected results for shared components that depend on thread variables, so leave it off unless you have measured a need.

Predefined variables and properties

Name Meaning

START.MS

JMeter start time in milliseconds. A property, also copied to a variable of the same name.

START.YMD

JMeter start time as yyyyMMdd.

START.HMS

JMeter start time as HHmmss.

TESTSTART.MS

Test start time in milliseconds.

COOKIE_name

When CookieManager.save.cookies=true (default false), each cookie is stored in a variable named with the prefix from CookieManager.name.prefix (default COOKIE_) followed by the cookie name.

JMeterThread.last_sample_ok

Reflects whether the last sample was successful; the component reference refers to it as ${JMeterThread.last_sample_ok} in the description of the JSR223 Sampler.

The START.* values reflect when JMeter itself started, not when the test began, and are mainly meant for file names such as a results file per run. ${__isPropDefined(START.HMS)} returns true. Variables named in the sample_variables property (for example SESSION_ID,REFERENCE, the value the properties reference lists and jmeter.properties shows as a commented example) are also saved in the results file, which is how a user id or token reference can be tied to a sample.

Pitfalls

  • A misspelt name silently stays literal. Look at the request in a listener.

  • Unescaped commas split arguments. Store long scripts and JSON bodies in a variable.

  • A trailing comma pair, as in ${__time(YMD,)}, is how an optional argument is skipped.

  • __P returns 1 if no default is given, which can mask a missing -J for a threads or loops value; always give an explicit default.

  • -J values do not reach remote servers; use -G in distributed runs.

  • Properties are read when evaluated, so a __setProperty publisher must run first.

  • Thread-dependent functions evaluated at Test Plan level, or in configuration elements, return wrong values.