eBook > The JMeter Playbook: Build, Scale, and Optimize Performance Tests
Logic Controllers
Logic Controllers determine when and how samplers are executed. They let you model realistic user flows that include branching, looping, grouping, and randomization.
Back to topSimple Controller
The most basic controller. It simply groups samplers together for logical/organizing clarity. It does not amend execution order.
Thread Group
├── Simple Controller - "Login Flow"
│ ├── GET /login-page
│ └── POST /login
└── Simple Controller - "Browse Products"
├── GET /products
└── GET /products/${productId}
Back to top
Loop Controller
Repeats its child elements a specified number of times within a single thread iteration.
| Setting | Description |
|---|---|
| Loop Count | Number of repetitions (or -1 for infinite) |
Example: Repeat a Search 5 Times
Thread Group (1 iteration)
└── Loop Controller (loop count = 5)
└── GET /api/search?q=${__RandomString(5,abcdefg,)}
Each thread sends 5 search requests per iteration with random 5-letter queries.
Back to topIf Controller
Executes its children only if a condition is true.
| Setting | Value |
|---|---|
| Condition | ${__groovy(vars.get("userType") == "admin")} |
| Interpret condition as variable expression | Unchecked (use full expression) |
Important: Always use
${__groovy(...)}or ${__jexl3(…)} functions for conditions. The legacy JavaScript interpreter is slower, consumes more resources, and is removed in newer Java versions.
Example: Admin-Only Actions
Thread Group
├── POST /login
│ └── JSON Extractor → ${userType}
├── If Controller - ${__groovy(vars.get("userType") == "admin")}
│ ├── GET /admin/dashboard
│ └── POST /admin/settings
└── GET /profile
Only threads where the login response returns userType = admin will execute the admin requests.
Transaction Controller
Groups samplers into a logical transaction and reports a single aggregate response time for its children. This is essential for measuring end-to-end user operations. For example, you will have the answer to how much time did the whole flow take instead of having to manually add all relevant Samplers response times.
| Setting | Description |
|---|---|
| Generate parent sample | If checked, child samples appear as sub-results under one parent in reports |
| Include duration of timer and pre-post processors | Usually unchecked - you want only sampler time, by default JMeter doesn’t include it into response time as well as sleep time from Timers |
Example: Measure “Checkout” Transaction Time
Thread Group
└── Transaction Controller - "Checkout"
├── POST /cart/add
├── GET /cart
├── POST /checkout
└── GET /order-confirmation
In the Aggregate Report, you will see a single Checkout row with the combined response time of all four requests.
While Controller
Repeats children while a condition is true. Useful for polling endpoints.
While Controller - ${__groovy(vars.get("status") != "COMPLETE")}
├── GET /api/job/${jobId}/status
│ └── JSON Extractor → ${status}
└── Constant Timer (2000 ms)
This polls every 2 seconds until the job status becomes COMPLETE.
ForEach Controller
Iterates over a set of variables with a common prefix. Often used after a Regular Expression Extractor with Match No. = -1 (extract all).
| Setting | Description |
|---|---|
| Input variable prefix | productId (JMeter expects productId_1, productId_2, …) |
| Output variable name | currentProductId |
GET /api/products
└── JSON Extractor → ${productId} (Match No. = -1)
ForEach Controller (prefix=productId, output=currentProductId)
└── GET /api/products/${currentProductId}/details
Back to top
Random Controller
Picks one random child sampler to execute per iteration. Useful for simulating users who randomly browse different pages.
Random Controller
├── GET /products/electronics
├── GET /products/clothing
├── GET /products/books
└── GET /products/home
Back to top
Interleave Controller
Executes one child per iteration in round-robin order. This means it cycles through children sequentially one at a time.
Example: Round-Robin Browsing
Thread Group
├── Interleave Controller
│ ├── GET /products/electronics
│ ├── GET /products/clothing
│ └── GET /products/books
└── GET /cart ← runs every iteration
| Thread Iteration | Samplers Executed |
|---|---|
| 1 | GET /products/electronics → GET /cart |
| 2 | GET /products/clothing → GET /cart |
| 3 | GET /products/books → GET /cart |
| 4 | GET /products/electronics → GET /cart ← cycle restarts |
| 5 | GET /products/clothing → GET /cart |
| … | … |
Notice that GET /cart executes on every iteration because it is a sibling of the Interleave Controller, not a child. Only the samplers inside the controller are subject to round-robin selection.
Compare this with the Random Controller, which picks a child at random each time. The Interleave Controller guarantees that every child gets an equal share of executions in a predictable, repeating sequence.
Back to topModule Controller
References another controller in the test plan by name. This lets you reuse common flows (like a login sequence) without duplication. Normally, it’s recommended for using together with Test Fragments.
Back to topController Summary Table
| Controller | Purpose |
|---|---|
| Simple | Grouping / organisation |
| Loop | Repeat N times |
| If | Conditional execution |
| Transaction | Group children into one reported transaction |
| While | Repeat until condition is false |
| ForEach | Iterate over extracted variables |
| Random | Pick one random child |
| Interleave | Round-robin one child per iteration |
| Module | Reuse another controller |
Best Practices
- Use Transaction Controllers to measure business-level operations (login, checkout, search).
- Name controllers descriptively - they appear in reports. Don’t forget to apply naming convention to children.
- Prefer
__groovyor__jexl3conditions in If Controllers for performance and compatibility. - Combine ForEach with extractors to iterate over dynamic lists from server responses.
- Keep controller nesting shallow - deeply nested trees are hard to debug.
Summary
- Logic Controllers shape the execution flow of your test plan.
- Transaction Controllers are critical for meaningful SLA reporting of business “transactions” and/or end-to-end flows.
- If Controllers enable conditional paths based on runtime data.
- Loop, While, and ForEach Controllers handle repetition patterns.
- Random and Interleave Controllers add realistic variation.
Now let’s see how we can generate test reports.