skip to content

Variables Versus Properties

A variable is a per-thread copy no other thread can read; a property is JVM-wide and shared. This distinction is the single most reliable discriminator in a JMeter interview.

on this pageshow

explore

questions

6

In JMeter, what is the difference in scope between a variable and a property?

level: juniorimportance: must knowfreq 85%

answer

  1. Two separate stores, not one
  2. Ask who else can read it
  3. Think base URL versus session token
  4. ${varName} and ${__P(name)} read different maps

basics

~10 s

A JMeter variable is a per-thread copy that no other thread can read or change. A JMeter property is a single JVM-wide value that every thread in the run shares.

solid answer

~50 s

JMeter keeps two separate stores. **Variables** live in a `JMeterVariables` object that `JMeterContextService` holds in a `ThreadLocal`, so each thread gets its own copy; a `sessionToken` written by one thread is invisible to the rest. **Properties** live in one static `Properties` map inside `JMeterUtils`, shared by the whole JVM for the length of the run. You read a variable with `${varName}` and a property with `${__P(name,default)}` — a bare `${...}` never reaches the property map. A `User Defined Variables` element seeds a variable into every thread; a property arrives from a property file or from `${__setProperty(name,value)}`. The working rule: a run-wide **base URL** that all threads must agree on is a property, while a **session token** belonging to one simulated user is a variable. Store the token in a property and threads overwrite each other's login.

code

properties · 3 lines
properties
# user.properties - loaded once at startup, shared by every thread
base.url=shop.internal.example
base.port=443

go deeper

for a junior

Recall the one-line discriminator: a variable is per-thread, a property is JVM-wide. Be ready to give the syntax for each, ${varName} for a variable and ${__P(name,default)} for a property.

for a middle

Explain the mechanism rather than the rule. Variables sit in a per-thread JMeterVariables object, properties in one static map, and a bare ${...} only ever reaches the first of those.

for a senior

Show you have debugged this in a real run. Describe the symptom when per-user state is kept in a property: threads silently overwrite one another, so the plan passes with one thread and fails intermittently with fifty.

for a principal

Own the convention so nobody rediscovers it. Decide which values are run-wide inputs and which are per-user state, and make the split visible in the plan itself, with property files for the former and User Defined Variables and extractors for the latter.

JMeter stores parameter values in two places that look almost identical inside a plan and behave nothing alike once threads are running. Telling them apart is the single most reliable discriminator in a JMeter interview, because almost every "it worked with one thread and broke with fifty" story traces back to the wrong one being used. ## Two stores with different owners A **variable** lives in a `JMeterVariables` object. `JMeterContextService` keeps the per-thread context in a `ThreadLocal`, so every thread a Thread Group starts is handed its own `JMeterVariables` instance. When thread 7 writes `sessionToken`, it writes into thread 7's map and nowhere else. Threads 1 through 6 cannot see the value, cannot overwrite it, and are not slowed down by it. A **property** lives in one static `Properties` object held by `JMeterUtils`. There is exactly one of these per JVM for the whole run. Every thread in every Thread Group reads and writes the same entries, and a value written at 10 seconds into the run is still there at 10 minutes. ## Reading and writing each one | | Variable | Property | |---|---|---| | Read syntax | `${varName}` | `${__P(name,default)}` | | Visible to | one thread | every thread in the JVM | | Typical source | `User Defined Variables`, an extractor, a `Counter` | `jmeter.properties`, `user.properties`, `${__setProperty(...)}` | | Lifetime | the thread that owns it | the whole run | | Two threads writing the same name | independent copies | last writer wins | The syntax is the giveaway in a plan review. A bare `${name}` is always a variable lookup. A property is never reachable that way — it needs the `__P` function, because the property map is a different object entirely. ## A run-wide base URL versus a per-thread session token The worked case that makes the split obvious is a plan that hits a staging host and logs each virtual user in. - The **base URL** is one value the entire run should agree on. It is chosen before the run starts, nothing in the plan changes it, and every thread wants the identical string. That is a **property**: put `base.url=https://shop.internal.example` in a property file and read it as `${__P(base.url,http://localhost:8080)}`. - The **session token** is produced during the run, belongs to exactly one simulated user, and is meaningless to any other thread. That is a **variable**: an extractor writes `sessionToken` into the thread's own map and later samplers read `${sessionToken}`. Invert the two and both break, but only one breaks loudly. A base URL kept in a variable merely has to be repeated in every Thread Group. A session token kept in a property is overwritten by whichever thread logged in most recently, so threads start sending each other's token. With one thread it passes every time. With fifty it fails intermittently and the failure moves around, which is why this shows up as a debugging story rather than a design review finding. ## What the split rules out - A variable cannot be used to hand a value from one thread to another. There is no shared variable; there are N private copies. - A property cannot hold anything that differs per simulated user, because there is only one slot for the key. - `${__P(name)}` will not find a `User Defined Variables` entry, and `${varName}` will not find a property file entry. They read different maps. - Nothing in a variable survives the run. Nothing in a property is private. ## Where the values come from Properties are seeded from files that JMeter reads at startup and can also be written during the run with `${__setProperty(name,value)}`, which is how a plan publishes a value from one thread to all the others. Variables are seeded per thread by a `User Defined Variables` config element, and are then added to during the run by extractors and by elements such as `Counter` and `Random Variable`, all of which write their output into the calling thread's own variables map. This is worth stating explicitly because it catches people out: even `Counter`, which can be configured so that all threads advance one shared sequence, still delivers its result as a per-thread **variable**. The sharing is in the counting, not in the storage. Whenever you see a value arriving as `${something}` in a plan, it is a variable and therefore private to the thread reading it, whatever produced it.

  • Does a User Defined Variables element create one shared value or one per thread?
    One per thread. The element seeds its entries into each thread's own JMeterVariables copy, so a later change made by one thread never reaches another. It is a source of variables, not of properties, and its contents are gone when the run ends.
  • Can ${__setProperty(name,value)} be used to hand a value from one thread to another?
    Mechanically yes: it writes into the JVM-wide property map that every thread can read with ${__P(name)}. But it is a broadcast to all threads rather than a channel to one, so a second writer overwrites the first and a reader has no way to tell whose value it got.
  • Why does ${baseUrl} come through as the literal text ${baseUrl} when base.url is set in user.properties?
    Because the two syntaxes read different stores. A bare ${...} is a variable lookup and never consults the property map, and the names differ as well; an unresolved reference is returned unchanged, so the field receives the literal ${baseUrl}. Reading a property requires the function form, ${__P(base.url,default)}.

A property is the noticeboard in the office lobby: one board, and everyone who walks past reads the same notice. A variable is the notepad on each person's own desk. Same kind of paper, but what you write on yours stays yours, and fifty people can write fifty different things at once without anyone colliding.

saying these in an interview costs you the question

  • Treats variable and property as two names for the same thing
  • Stores a per-user session token in a property, so threads overwrite each other
  • Expects a variable written by one thread to be visible to another thread
  • Thinks ${__P(name)} can read a User Defined Variables entry
  • Believes a variable set during a run persists into the next run
open as a page

Which property files does JMeter load at startup, and in what order?

level: middleimportance: must knowfreq 60%

basics

~10 s

JMeter loads bin/jmeter.properties first, then the file named by its user.properties key, whose entries override it, then the file named by its system.properties key, which updates the JVM's system properties instead.

open as a page

In JMeter, what does ${__P(base.url)} return when base.url is not set?

level: middleimportance: should knowfreq 45%

basics

~10 s

The literal string 1. JMeter's __P function uses 1 as its built-in default when no second argument is given, so an unset property silently resolves to 1 rather than raising an error.

open as a page

In JMeter, how do you make a value captured by one thread readable by all threads?

level: seniorimportance: should knowfreq 40%

basics

~10 s

Write it into the property map with ${__setProperty(name,value)} and read it anywhere with ${__P(name)}. Variables cannot cross threads, because every thread holds its own private copy.

open as a page

Why can a value set in JMeter's system.properties be invisible to ${__P(...)}?

level: seniorimportance: should knowfreq 30%

basics

~10 s

Because system.properties updates the JVM's system properties, which JMeter consults only as a fallback. Any key already present in jmeter.properties or user.properties shadows it, so the last file loaded still loses.

open as a page

What changes in JMeter's Counter when Track counter independently for each user is ticked?

level: middleimportance: nice to knowfreq 22%

basics

~10 s

Ticked, every thread counts its own private sequence from the start value. Unticked, all threads advance one shared synchronized sequence, so each iteration anywhere in the run takes the next distinct number.

open as a page