Skip to content

JMeter Functions and Variables Guide

Master JMeter functions and variables: syntax rules, thread-local vars vs properties, CSV Data Set, __P for CLI, and common parameterization patterns.

Difficulty
intermediate
Guide type
reference
Estimated read time
12 min read
Last verified version
Verified JMeter 5.6

Functions and variables are how Apache JMeter turns a static tree of samplers into data-driven load. This guide explains syntax rules, the difference between variables and properties, the functions you will use most, CSV and file input, scripting functions, parameterization for CLI/CI, sharing data across threads, and common mistakes - grounded in the official Functions and Variables chapter and Best Practices.

For the exhaustive function table and per-function parameters, always use the full reference.

A function call looks like:

\${__functionName(var1,var2,var3)}

Rules from the manual:

  • Parentheses surround parameters, for example \${__time(YMD)}.
  • Functions that need no parameters may omit parentheses: \${__threadNum} is equivalent to \${__threadNum()}.
  • If a parameter contains a comma, escape it with \, otherwise JMeter treats the comma as a parameter delimiter.
    Example: \${__time(EEE\, d MMM yyyy)}
  • Unescaped commas produce confusing errors (the docs show JavaScript Math.max(2,5) splitting into two parameters).
  • Functions can appear in sampler fields, config elements, and many other test element fields.
  • Case sensitivity applies to functions, variables, and properties.
  • JMeter trims spaces from variable names used when storing function results (for example a trailing space in a third argument name is trimmed).

Reference a variable as:

\${VARIABLE}

Important documented behaviour:

If an undefined function or variable is referenced, JMeter does not report/log an error - the reference is returned unchanged. If UNDEF is not defined, \${UNDEF} stays \${UNDEF}.

That makes missing extractors easy to miss unless you assert on values or use extractor default values like NOT_FOUND.

When a \ precedes a variable in a Windows path, escape carefully or JMeter may not interpolate the variable. The manual recommends using / as the separator (JVMs on Windows accept it), or proper escaping of backslashes.

From the official note:

  • Variables are local to a thread.
  • Properties are common to all threads.
  • Properties are referenced with __P or __property, not \${PROP} alone (unless you also mirror them into variables).
VariablesProperties
ScopePer threadWhole JMeter JVM (all threads)
Typical set byExtractors, CSV Data Set, vars.put in scripts, UDVs-J CLI, user.properties, __setProperty, GUI props
Typical read\${name}\${__P(name,)} or \${__P(name,default)}
Use forTokens, CSV columns, per-user stateHost, threads, env flags, cross-thread signals

Because variables do not cross threads by design, the best practices chapter lists options when a value is only known at runtime:

  • Store it as a property (global to the instance)
  • Write to a file and re-read
  • Use bsh.shared (legacy BeanShell patterns)
  • Write custom Java classes

For values known before the test starts, prefer parameterization with properties (-J / -q) rather than cross-thread writes.

Grouped loosely like the official reference (Information, Input, Calculation, Scripting, Formatting, …).

FunctionRoleExample
__threadNumCurrent thread number\${__threadNum}
__threadGroupNameThread group name (newer JMeter)\${__threadGroupName}
__samplerNameCurrent sampler label\${__samplerName}
__machineIP / __machineNameInjector identity (useful in distributed logs)\${__machineName}
__timeCurrent time with format\${__time(yyyy-MM-dd)}
__timeShiftTime plus offsetsee reference for args
__log / __lognLog while evaluatingdebug carefully under load
FunctionRoleExample
__RandomRandom integer in range\${__Random(1,1000,myRand)}
__RandomStringRandom string\${__RandomString(10,abcdef)}
__UUIDType-4 UUID\${__UUID}
__counterIncrementing counter\${__counter(TRUE,)}
__RandomDateRandom date in rangesee reference
__digestHash digests (SHA, MD5, …)see reference

Many calculation functions accept an optional variable name argument to store the result as well as return it - check each function’s parameter list in the reference.

FunctionRoleExample
__PProperty with optional default\${__P(threads,10)}
__propertyLonger form property accesssee reference
__setPropertySet a property during the testuse sparingly; concurrency-aware
__VEvaluate nested variable names\${__V(user_\${n})}

__P is the backbone of CLI/CI parameterization (best practices § parameterising tests):

LOOPS=\${__P(loops,10)}
Terminal window
jmeter -n -t plan.jmx -Jloops=12
FunctionRole
__substringSlice a string
__urlencode / decode helpersEncode query parts
__splitSplit into variables (escape commas in args)
__dateTimeConvertConvert date formats
__intSum / __longSumArithmetic
FunctionRole
__StringFromFileRead a line from a file
__FileToStringRead entire file (payloads, certs - watch size)
__CSVReadOlder CSV read helper
__XPathXPath against a file
__StringToFileWrite a string to a file (side effects!)

For multi-user login data, official best practices prefer the CSV Data Set Config element over ad-hoc scripting (see next section).

FunctionNotes
__groovyRun Groovy (preferred modern scripting)
__BeanShellLegacy; best practices advise moving to JSR223
__javaScriptLegacy Nashorn-era; not ideal for intensive load

Best practices: for intensive load, use languages whose engine implements Compilable - Groovy does; BeanShell/JavaScript were called out as poor choices for hot paths as of the JMeter 3.1-era guidance still published in the manual.

Prefer JSR223 elements with Cache compiled script and vars.get("name") inside scripts instead of embedding \${name} in cached script text (caching would freeze the first interpolated value).

CSV Data Set Config (primary parameterization tool)

Section titled “CSV Data Set Config (primary parameterization tool)”

From best practices - User variables:

  1. Create a text file of usernames/passwords separated by commas (same directory as the plan is a common pattern).
  2. Add CSV Data Set Config; set variable names (for example USER, PASS).
  3. Replace login fields with \${USER} and \${PASS}.
  4. The CSV Data Set reads a new line for each thread (for that documented multi-user login pattern).

Configure recycle/stop-thread behaviour according to whether you want data to loop or threads to stop when the file ends - see the component reference for CSV Data Set fields.

Large random datasets: create files ahead of time and read with CSV Dataset rather than generating expensive random data on the fly for every sample.

User Defined Variables and Test Plan variables

Section titled “User Defined Variables and Test Plan variables”
  • User Defined Variables config elements and Test Plan-level variables define name/value pairs available to the plan.
  • Matching with the HTTP(S) recorder’s replacement feature is case-sensitive when abstracting server names into \${server} (best practices - recorder).
  • For CLI overrides, bind those values to __P as shown above.
  • Multiple property files: pass with -q when many properties change together.

Where evaluation happens (practical implications)

Section titled “Where evaluation happens (practical implications)”

Functions and variables are evaluated when JMeter needs the field value for a sample or config - not “once at plan load” for every case. Implications:

  • \${__UUID} on a sampler produces a new id each time that field is evaluated for a sample.
  • Putting \${__Random} in HTTP Defaults may not do what you expect if the default is resolved differently than a per-sampler field - prefer placing dynamic calls on the sampler that should change.
  • Extractors run as post-processors after a sampler; downstream samplers see new \${token} values.

When debugging, use View Results Tree (scripting phase only) and Debug Sampler / Debug PostProcessor patterns to print variables. Disable them for load.

\${__P(host,localhost)}
\${__P(port,443)}
\${__P(protocol,https)}

Wire HTTP Request Defaults to these values; CI passes -Jhost=staging.example.com.

  1. Login sampler → JSON/Regex extractor → accessToken
  2. Header Manager: Authorization = Bearer \${accessToken}
  3. Keep accessToken as a variable (per thread). Only promote to a property if you intentionally share one token across threads.
user_\${__threadNum}_\${__time(HHmmss)}@example.com

Or precompute in CSV for repeatability.

If you create user_1, user_2, …:

\${__V(user_\${__threadNum})}

\${__counter(TRUE,)} (see reference for TRUE/FALSE per-thread vs global counter behaviour).

In distributed mode:

  • Each worker is a separate JVM → properties and variables do not sync across workers.
  • __machineName / IP help label which injector produced a sample when analyzing combined logs.
  • CSV files must exist on each worker; they are not shipped with the plan.
  • -Gprop=value sets a property on remote servers; -J is for the client side - know which side reads \${__P(...)} for your plan design.
  1. Prefer CSV over heavy __groovy on every sample when data can be precomputed.
  2. Prefer JSR223 Groovy with compile cache over BeanShell function calls in hot paths.
  3. Do not log (__log) on every sample at scale.
  4. Escape commas in function parameters.
  5. Assert critical \${vars} so literal \${token} strings cannot look like success.
  6. Remember undefined → unchanged string.
  7. For intensive scripts, use vars.get / props.get inside JSR223, not \${} inside cached scripts.
  8. Keep property names stable for CI; document them in the plan README.
FlagEffect
-Jname=valueSet JMeter property on client
-Gname=valueSet property on remote servers (distributed)
-q fileAdditional property file
-S / system propsSee Getting Started override docs for full CLI list

Thread Group example:

Number of Threads = \${__P(threads,1)}
Ramp-up = \${__P(rampup,1)}

Safe defaults for local runs; CI raises threads.

When a value is wrong, isolate evaluation without creating a load-test anti-pattern:

  1. View Results Tree (scripting only) - inspect request after variable substitution.
  2. Debug Sampler + Tree - dump variables for the thread at that point in the tree.
  3. Extractor default values - NOT_FOUND is easier to spot than a silent empty string.
  4. Response Assertion on login - fail fast before thousands of dependent calls.
  5. Temporary \${__log(message)} - remove before load; logging every sample is expensive.

Never leave Debug Sampler or View Results Tree enabled for the CLI performance run you archive in CI.

Functions inside controllers and deferred evaluation

Section titled “Functions inside controllers and deferred evaluation”

Some fields are evaluated later than others (for example, certain controller conditions or script elements). If a function appears to run “too often” or “too early”:

  • Move the dynamic expression onto the sampler field that should change per sample.
  • Prefer post-processors to set a variable once per response, then reference \${var} downstream.
  • For Once Only login, ensure extractors sit under the login sampler, not under a later random controller path that might skip login.

When using If Controller or similar, condition strings that embed functions should be tested with one thread and Tree view so you see the evaluated branch.

For shared environments, maintain property files rather than long -J lists:

Terminal window
jmeter -n -t plan.jmx -q env/staging.properties -l out.jtl -e -o report/

Document keys in the repository (threads, rampup, host, usersFile). Official best practices encourage user.properties overrides instead of editing stock jmeter.properties for durable configuration - the same idea scales to environment-specific -q files in CI (CI/CD guide).

  1. Read syntax + variables vs properties on this page.
  2. Practice \${__Random} and \${__UUID} on a single HTTP sampler; confirm in View Results Tree.
  3. Add CSV Data Set for two users.
  4. Replace host/threads with \${__P}.
  5. Extract a token and pass it to the next sampler.
  6. Skim the complete function list for niche helpers (__digest, __timeShift, …).
  7. When scripting grows past a one-liner, move to JSR223 Groovy elements per best practices.
  8. Wire the same plan into a CLI command with -J overrides and confirm defaults still work offline.

What is the difference between a JMeter variable and a property?

Section titled “What is the difference between a JMeter variable and a property?”

Variables are thread-local; properties are shared across all threads in the JVM. Read properties with \${__P(name,default)}. Read variables with \${name}.

Why does my function argument break at a comma?

Section titled “Why does my function argument break at a comma?”

Commas separate parameters. Escape literal commas as \, inside the parameter, as shown in the functions manual for __time formats.

Why do I still see \${token} in the request?

Section titled “Why do I still see \${token} in the request?”

The variable was never set (extractor failed or wrong name). JMeter leaves undefined references unchanged and does not always error.

How do I pass values between thread groups?

Section titled “How do I pass values between thread groups?”

Not with ordinary variables. Use properties, files, or other documented sharing approaches in best practices. Prefer design that avoids cross-group chatty sharing.

Should I use __CSVRead or CSV Data Set Config?

Section titled “Should I use __CSVRead or CSV Data Set Config?”

For multi-user data rows, official best practices demonstrate CSV Data Set Config. __CSVRead remains a function for specific cases; see the reference.

For intensive load, the manual advises JSR223 with Groovy (Compilable) and moving off BeanShell. Existing BeanShell may still run; new work should prefer Groovy.

How do I set threads from Jenkins or GitHub Actions?

Section titled “How do I set threads from Jenkins or GitHub Actions?”

Use \${__P(threads,10)} in the Thread Group and pass -Jthreads=50 on the jmeter -n command in CI (CI/CD guide).

On this page