The Loop Controller in JMeter
How to repeat part of a test exactly as many times as you need, how it differs from the Thread Group loop, how the numbers multiply, and how to use it without distorting your results.
A chai seller at a railway station does not rebuild his stall for every customer. He sets up once, and then repeats the same small routine again and again: take the order, pour the tea, collect the money. A good load test works in much the same way. A real user logs in once, but may then search ten times, open twenty product pages, or upload five photos in a row. If you wrote out each repeated step by hand, your test would become long, slow to edit, and easy to get wrong. In Apache JMeter, the element that repeats a group of steps for you is called the Loop Controller.
This guide teaches the Loop Controller from zero. You do not need earlier JMeter knowledge. We begin with what a controller is, then look at every setting on the Loop Controller screen, then follow what happens inside JMeter on each pass of a loop. After that we cover the topics that separate a careful engineer from a beginner: how loop counts multiply, how to get a different value on every pass, how to break out of a loop early, what a loop does to your load and your reports, and the mistakes that quietly distort results.
WWhat Is a Loop Controller?
It is a JMeter element that runs everything placed inside it a set number of times, one pass after another, before moving on.
Starting with the basics
Apache JMeter is a free, open-source tool written in Java that measures how well a system behaves when many users use it at the same time. This is called load testing or performance testing. A JMeter test is arranged as a tree called a Test Plan. The pieces inside the tree are called test elements. Each virtual user is a thread, which is a small worker that walks through the tree independently of the others.
A Sampler is the element that sends one request, such as an HTTP call, and records the answer. Each request and answer pair is one sample. A Controller is an element that decides how and when the samplers beneath it run. Some controllers only group steps together, and others repeat steps, skip steps or choose between them. The Loop Controller is the simplest repeating controller. You give it a number, and it runs its children that many times.
What the Loop Controller really does
The Loop Controller has one main job: repeat. Whatever you place under it, whether one sampler or a long chain of samplers, timers and extractors, is performed from top to bottom, then performed again, until the loop count is reached. Only then does the virtual user move on to the next element after the loop. It does not send anything itself, it does not judge anything, and it does not record anything. It simply controls the flow.
Think of a gym instructor who tells a class, “Do ten push-ups, then move on to the next exercise.” The instructor does not do the push-ups. The instructor only sets how many times the group repeats the movement. The Loop Controller is that instructor, and the samplers beneath it are the exercise.
Why it matters
Loops decide how much work each virtual user performs. If you accidentally set a loop to a hundred instead of ten, your server may receive ten times the traffic you planned. If you forget a loop, your test may send far fewer requests than a real user would. Because loops multiply, a small change can create a very large change in load. Understanding the Loop Controller is therefore not a detail. It is a core part of shaping the traffic your test creates.
The Loop Controller repeats a section of your test. Everything beneath it runs again on each pass, and its loop count tells JMeter how many passes to make.
TThe Controller Family: Where Loops Fit
JMeter has a whole family of controllers. Seeing the family makes it clear what the Loop Controller is for, and what it is not for.
Two kinds of controllers
JMeter splits controllers into two groups. Samplers do real work and are sometimes loosely called controllers because they sit in the same part of the tree, but they are really the workers. Logic Controllers are the managers. They hold other elements and decide the order, the count and the conditions under which those elements run. The Loop Controller belongs to the second group.
Loop Controller
Runs its children a fixed number of times, or forever if you ask.
While Controller
Keeps repeating as long as a condition stays true, such as “job not finished yet”.
ForEach Controller
Repeats once for every item in a numbered list of variables, such as a list of product ids found in a response.
If Controller
Runs its children only when a condition is true.
Interleave Controller
Runs just one child per pass, rotating through them.
Random Controller
Picks one child at random on each pass.
Once Only Controller
Runs its children only once per virtual user, such as a login step.
Transaction Controller
Bundles several samplers into one measured business step.
When to choose which
The Loop Controller is the right tool when you know in advance how many times a section should repeat. If the answer depends on something that happens during the test, such as waiting for a status to change, the While Controller fits better. If the number of repeats depends on the length of a list returned by the server, the ForEach Controller fits better. Using a Loop Controller where a While or ForEach Controller belongs is a common source of tests that run too few or too many passes.
The Loop Controller counts. It never looks at the responses. If the repeat decision depends on what the server says, you need a different controller or a way to break out of the loop, both covered later.
WWhere the Loop Controller Sits in a Test Plan
The position of a Loop Controller in the tree decides what it repeats and what other elements can see inside it.
A typical tree
A normal test starts with the Test Plan, then a Thread Group that sets how many virtual users run and how many times each one repeats the whole scenario. Beneath the Thread Group you place samplers and controllers in the order a real user would act. A Loop Controller is added as a child of the Thread Group or of another controller, and the samplers to repeat are placed under it.
flowchart TD
A[Test Plan] --> B[Thread Group]
B --> C[HTTP Request Login]
B --> D[Loop Controller Browse Products]
D --> E[HTTP Request Search]
D --> F[HTTP Request View Product]
D --> G[Constant Timer]
B --> H[HTTP Request Logout]
B --> I[Listener]
How the user experiences it
Reading the tree above from top to bottom, each virtual user logs in once. It then enters the Loop Controller and performs search, view and a pause. It then does so again, as many times as the loop count says. When the loop is complete, it moves down to logout. The Loop Controller wraps only the section you want to repeat, so the login and logout stay outside it.
Scope in one idea
Scope means which samplers an element affects. An element affects its own level and everything beneath it, like a notice pinned on one floor of a building: everyone on that floor sees it, and other floors do not. A timer placed directly under the Loop Controller applies to every sampler in the loop. A timer placed under the Thread Group applies to every sampler in the Thread Group, including those outside the loop. Choosing where to place each helper is a design decision.
Picture a restaurant with a set menu. Welcoming the guest and presenting the bill happen once. Serving each of the five courses is the repeated part. The Loop Controller is the box drawn around the courses. Anything inside the box repeats for every course. Anything outside happens just once per visit.
Rename the Loop Controller to say what it repeats, such as Browse Products Loop. A clear name makes both the plan and the reports easier to read.
TTour of the Loop Controller Screen
The screen is small, which is part of its charm. A few fields do all the work.
The fields
| Field | What it does | Watch out for |
|---|---|---|
| Name | The label shown in the tree and in reports | Leaving the default name makes several loops hard to tell apart |
| Comments | A free note for the next person who reads the plan | Unused, but very useful for explaining why a count was chosen |
| Loop Count | How many times the children run | A very large number multiplies traffic enormously |
| Infinite | A tick box that makes the loop repeat without end | Needs another way to stop the test, such as a time limit on the Thread Group |
Giving the count as a value or a variable
The loop count box accepts a plain number, but it also accepts a variable or a function. A variable is a named value, written between a dollar sign and curly brackets, that JMeter swaps for a real value at run time. This means the count could come from a data file, from a value extracted from a response, or from a setting passed on the command line. A popular approach is to read the count from a property so the same test plan can run a light version for a quick check and a heavy version for the real run, without editing the file.
What a count of zero or a negative number means
A count of zero means the children are skipped entirely. A negative count, such as minus one, is treated as infinite, the same as ticking the Infinite box. Be careful here. If a variable that you use for the count is empty or holds text that is not a number, the loop may behave in a way you did not intend. Always check the value with a debugging element before trusting it.
The loop index
The Loop Controller also exposes a built-in variable that tells you which pass you are on. Its name is made from the controller’s name. If your Loop Controller is called Browse Loop, the variable is the name wrapped with two underscores and the word idx, preceded by the prefix jm. The first pass has the number zero, the second pass has the number one, and so on. Because the name of the variable includes the name of the controller, renaming the controller changes the variable. This is one more reason to choose a stable, simple name early and to avoid spaces and unusual characters.
Pass numbers start at zero, not at one. If you show the index on a page or use it to pick a row, remember that the first pass is zero. Mixing up zero-based and one-based counting is a classic off-by-one slip.
HHow Looping Works Internally
Behind the scenes, JMeter treats each controller as a small machine that hands out its children one at a time. Seeing that machine explains many puzzling behaviours.
One thread, one walk through the tree
Every virtual user thread asks the Thread Group for the next thing to run. The Thread Group asks its first child, and each controller in turn hands over its own next child, until a sampler is reached. That sampler runs, and the thread asks again. When a controller runs out of children, it tells its parent it is done, and the parent moves to its next child. The Loop Controller adds one extra rule: when its last child is finished, it checks whether more passes remain, and if so it starts again from its first child instead of reporting that it is done.
flowchart TD
A[Thread enters Loop Controller] --> B{More passes left}
B -->|Yes| C[Reset children and set index]
C --> D[Run each child top to bottom]
D --> E[Add one to the pass number]
E --> B
B -->|No| F[Leave loop and run next element]
What is reset on each pass
At the start of each pass, the controller notifies the elements inside it that a new iteration has begun. Some elements react to this signal. A CSV Data Set Config element placed inside the loop reads its next row of data. A Counter element adds one. Controllers nested inside, such as an Interleave Controller, move forward in their own order. Elements that do not need to react simply run again with whatever values are current.
Each thread has its own loop
The loop state belongs to each virtual user separately. If a Loop Controller is set to five passes and you run a hundred threads, each thread makes five passes of its own, and the total is five hundred passes. The threads do not share a counter and they do not wait for each other. Thread number seven may be on its fourth pass while thread number twelve is on its first.
Imagine a hundred runners on a hundred separate tracks, each told to run five laps. Each runner counts their own laps. One runner finishing early does not change how many laps another runner needs to run.
Passes are not free
Every pass sends real requests. JMeter does not remember what the last pass did and it does not skip work that was already done, unless you add elements that do so, such as a cache manager. This is a feature, because it lets you measure repeated work, and it is also a risk, because repeated identical requests may be answered from the server’s own cache, which can make response times look better than real, varied traffic would.
Teams that run long tests often notice that the first pass of a loop is slower than later ones, because connections are being opened and caches are being filled. They either ignore the first pass in analysis or add a short warm-up phase before the measured loop.
LLoop Controller Versus the Thread Group Loop Count
Beginners often see two places to set a repeat count and wonder which one to use. They do different jobs, and they combine by multiplying.
Two kinds of repeating
The Thread Group has its own loop count. It tells each virtual user how many times to run the entire scenario from the first element to the last. The Loop Controller repeats only the section beneath it, and the rest of the scenario runs just once per scenario pass. One is the outer repeat for the whole story, and the other is an inner repeat for a single scene.
| Question | Thread Group loop count | Loop Controller |
|---|---|---|
| What repeats? | The whole scenario for each thread | Only the elements inside the controller |
| Where is it set? | On the Thread Group screen | On the Loop Controller screen |
| Can login run once outside it? | No, login repeats on every pass unless you use a Once Only Controller | Yes, place login before or outside the loop |
| Can it be infinite? | Yes, with the Infinite option, usually paired with a time limit | Yes, with its own Infinite tick box |
| Can there be several in one test? | Each Thread Group has one | As many as you like, even nested |
How the two combine
Suppose the Thread Group is set to repeat three times and a Loop Controller inside it is set to repeat four times, with one sampler inside. On each of the three scenario passes, that sampler runs four times. So one thread runs it twelve times. If there are ten threads, the sampler runs one hundred and twenty times in total. The counts multiply. They never add.
Choosing between them
Repeat the whole user journey
Use the Thread Group loop count, or a duration with an infinite count for time-based tests.
Repeat one section a fixed number of times
Use a Loop Controller around only that section.
Keep setup steps from repeating
Place them outside the loop, or inside a Once Only Controller when they sit under the Thread Group’s own repeat.
When someone says “my test sent far more requests than I planned”, the cause is very often a forgotten Thread Group loop count of more than one, multiplied by a Loop Controller. Always compute the total before running.
GGetting Different Data on Every Pass
A loop that sends the same request ten times is rarely realistic. This chapter shows how to make each pass different.
Why variety matters
Servers are clever about repeated questions. They may keep the answer ready in a fast memory called a cache, or they may reject duplicates, such as a second order with the same reference number. If every pass sends identical data, you measure the cache and the duplicate checks, not the real work. Real users search for different words, open different products and submit different forms, so a good loop feeds new data each time.
The tools for variety
CSV Data Set Config
Reads a row from a file each time it is told a new pass has begun, giving each pass a fresh set of values.
Counter
A config element that gives an increasing number on every pass. It can count across all users together, or separately for each user.
Loop index variable
The zero-based pass number exposed by the Loop Controller, handy for choosing which item to use.
Random functions
Built-in functions that give random numbers or strings, useful for search words and unique references.
Unique id function
Creates a fresh unique identifier for each use, good for order numbers.
Time functions
Produce the current time, useful when a request needs a timestamp.
Where you place the data element matters
A CSV Data Set Config reads its next line when the controller it sits in begins a new pass. If you place it directly under the Thread Group, it moves to a new row once per scenario pass, so every iteration of your inner loop sees the same row. If you place it inside the Loop Controller, it moves to a new row on every inner pass. Neither is wrong. They give different behaviour, and you should choose on purpose.
flowchart LR
A[Pass starts] --> B[CSV element reads next row]
B --> C[Variables hold new values]
C --> D[Sampler sends request with new values]
D --> E[Next pass starts]
E --> B
Running out of rows
The CSV element has a setting for what to do when the file ends. It can start again from the top, stop the thread, or stop the whole test. If a long loop consumes more rows than the file contains, recycling the file reuses old values, and stopping the thread cuts the loop short. Count your rows against the total passes: threads times scenario passes times loop passes, whenever each pass needs a new row.
Think of a teacher calling out names from a roll at the start of every class period. If the roll has thirty names but there are forty periods, the teacher must decide what to do: start the list again or stop calling. The CSV element faces the same choice when its file ends.
Before a big run, write the formula for how many rows you need on a sticky note. If the data file is shorter than the answer, either extend the file or choose the recycle option on purpose.
NNested Loops and the Mathematics of Load
A loop inside a loop is perfectly legal, and perfectly dangerous if you do not count carefully.
The multiplication rule
When one Loop Controller sits inside another, the inner section runs once for every pass of the outer one. The total number of runs of the innermost sampler is the product of every count above it: threads, Thread Group passes, outer loop passes, inner loop passes. A modest looking structure can produce a very large number.
| Threads | Thread Group passes | Outer loop | Inner loop | Runs of the innermost sampler |
|---|---|---|---|---|
| 10 | 1 | 5 | 4 | 200 |
| 50 | 2 | 10 | 10 | 10,000 |
| 200 | 5 | 20 | 20 | 400,000 |
| 500 | 10 | 50 | 50 | 12,500,000 |
Notice how the last row reached twelve and a half million requests from numbers that each look harmless. A tester who intended to send a few thousand could flood a staging environment by accident. This is why experienced engineers always multiply the counts before pressing start.
A real use for nesting
Nesting is useful when a real behaviour has two levels. Imagine a user who opens five search result pages, and on each page opens three product pages. The outer loop runs five times for pages. The inner loop runs three times for products. The search sampler sits in the outer loop, and the product sampler sits in the inner loop. The totals are five searches and fifteen product views per scenario pass, which matches the story.
flowchart TD
A[Outer Loop 5 passes] --> B[Search Results Page]
A --> C[Inner Loop 3 passes]
C --> D[Open Product Page]
Estimating request rate
Counts tell you the total number of requests. To understand the load per second, you also need the time each pass takes. If a pass takes two seconds, including pauses, and a hundred threads are all looping, the system sees about fifty requests per second per sampler in the loop. If you remove the pauses and the server answers in a tenth of a second, the same hundred threads create about a thousand requests per second. Pauses and response times are part of the loop’s arithmetic.
Do the multiplication on paper before every large test, and share the numbers with the team that owns the system under test. Surprises of this kind are what turn a planned test into an outage.
HHelpers Inside a Loop: Timers, Extractors and Assertions
Other elements behave in particular ways when they live inside a loop. Knowing the rules prevents silent mistakes.
Timers: pauses on every pass
A timer adds a pause before a sampler runs, to imitate a person reading or thinking. A timer placed inside a Loop Controller applies to every sampler in the loop, and it fires on every pass. If three samplers and one timer sit in the loop, the pause happens before each of the three, on every pass. If you wanted only one pause per pass, place the timer under the one sampler that should be preceded by it, or use a Flow Control Action sampler set to pause. Without any timer, a loop runs as fast as the server can answer, which is rarely realistic.
Extractors: values are overwritten
An extractor reads a value out of a response and stores it in a variable. Inside a loop, the same extractor runs on every pass, and each pass overwrites the variable from the previous pass. If you need to remember every value across the loop, give the extractor a way to store them separately, for example by building the variable name from the pass number, or by saving values to a file. If you only need the newest value, such as the latest token, the overwriting is exactly what you want.
Assertions: checking every pass
An assertion decides whether a response is correct. Inside a loop it checks every pass. A failure on pass seven is recorded as a failure for that pass only, and later passes continue unless you tell the Thread Group to stop on error. Because a loop multiplies samples, a tiny failure rate can still produce many failed samples, so watch percentages as well as counts.
Config elements inside a loop
Header and Cookie Managers
Normally placed at Thread Group level so they cover the whole scenario. Cookies carry over from one pass to the next, so a user stays logged in throughout the loop.
HTTP Request Defaults
Shared host and port settings for every sampler in scope, loop or not.
User Defined Variables
Set once at the start of the test, so they do not change from pass to pass.
Random Variable
Gives a new random value each time it is read, useful for varied choices on every pass.
Transaction Controllers and loops
A Transaction Controller bundles several samplers into one measured business step, such as “Add To Cart”. You can place it inside the loop, so each pass creates one transaction result, or you can place the loop inside the transaction, so the whole loop is measured as a single step. The first shows how each repetition performs, and the second shows how long the whole repeated activity took. Choose according to the question you want the report to answer.
Keep the Cookie Manager outside the loop at Thread Group level. If it is placed inside, it may be reset in ways that log the user out on every pass, which is a very confusing problem to chase.
OOnce Only, While, ForEach and the Other Controllers Compared
Loops rarely stand alone. They work best when combined with the other logic controllers, and each of those has its own rules.
The Once Only Controller inside a loop
The Once Only Controller runs its children a single time. Its behaviour inside a loop is easy to misread. When it sits under a Loop Controller, it runs on the first pass of that loop and is skipped on the others. If the outer structure starts the Loop Controller again, for example because the Thread Group repeats the scenario, then the Once Only Controller runs again on the first pass of that new start. So “once” means “once per start of the loop it lives in”, and not “once in the whole test”.
flowchart TD
A[Loop Controller 5 passes] --> B[Once Only Controller]
A --> C[HTTP Request Search]
B --> D[HTTP Request Fetch Token]
D -.->|runs on pass 1 only| C
While and ForEach for conditions and lists
The While Controller repeats as long as a condition is true. The condition is a small expression that you write, often based on a variable set by an extractor. A typical use is polling: ask for the status of a job until it says finished. The ForEach Controller repeats once for each item in a numbered set of variables, such as a list of product identifiers extracted from a response, handing the current item to the children on each pass. Use the Loop Controller only when the count is known in advance.
| Controller | Repeats when | Example |
|---|---|---|
| Loop Controller | For a count you decided in advance | Open ten search pages |
| While Controller | While a condition remains true | Check job status until finished |
| ForEach Controller | Once per item in a list of variables | Open every product found in a search |
| Once Only Controller | Only on the first pass of the loop it sits in | Fetch a token one time |
| Interleave Controller | One child per pass, in rotation | Alternate between three search types |
| Throughput Controller | For a chosen share of passes or executions | Run checkout for thirty percent of users |
A Loop Controller is like saying “knock on the door three times”. A While Controller is like saying “keep knocking until someone answers”. A ForEach Controller is like saying “knock on every door on this list”. The first has a fixed count, the second depends on what happens, and the third depends on how long the list is.
If you ever find yourself setting a huge loop count and then breaking out early when a condition is met, a While Controller is probably the cleaner design.
BBreaking Out of a Loop and Controlling the Flow
The Loop Controller itself has no exit condition other than its count. When you need to leave early, you combine it with other elements.
Why you might leave early
Imagine a loop that opens twenty pages of results, but the server answers an error on page six, or the account runs out of items. Carrying on for fourteen more passes wastes time, creates a pile of pointless failures, and pollutes your numbers. In real life, a user would stop. Your test should too.
The usual recipe
Place an If Controller inside the loop. Its condition checks a variable, such as “the response said no more results”. Inside the If Controller, place a Flow Control Action sampler. This special sampler does not send a request. It performs an action on the flow of the test, and it offers choices such as pausing for a given time, going straight to the next pass of the loop, breaking out of the current loop, starting the next scenario pass for this thread, or stopping the thread or the whole test. Choosing “break current loop” ends the Loop Controller early and continues with the element after it.
flowchart TD
A[Start pass] --> B[Search request]
B --> C{No more results}
C -->|Yes| D[Flow Control Action break current loop]
C -->|No| E[Open product page]
E --> F[Next pass]
D --> G[Continue after the loop]
F --> A
What the Thread Group does on errors
The Thread Group has a setting that decides what happens after any sampler fails. The choices are to continue, start the next scenario pass for that thread, stop that thread, stop the test gracefully, or stop the test immediately. This matters for loops. If you choose “start next thread loop”, a failure inside a loop jumps out of the whole loop and out of the rest of that scenario pass, which is a hidden early exit. If you choose “continue”, every remaining pass is attempted, even when an early failure makes the later ones meaningless. Think about what a real user would do after the first failure and pick the matching setting.
Go to next loop iteration
Skips the rest of this pass and starts the next one.
Break current loop
Leaves the nearest Loop Controller and carries on after it.
Start next thread loop
Abandons the rest of the scenario pass and begins the next one.
Stop thread
Ends this one virtual user while others carry on.
Pause
Waits for a stated number of milliseconds, handy for polling gaps.
Stop test
Ends the entire run, either gracefully or at once.
Breaking out of a loop on a failure also hides the failure from the later passes that never ran. Your sample counts will be lower than the plan predicted. Always compare actual counts to expected counts so silent early exits are noticed.
DData Flow and Lifecycle of a Looping Test
To trust a looping test, you need to know what carries over from pass to pass and what starts fresh.
What carries over
Variables
Values stored by extractors or functions stay until they are overwritten. A value from pass two is still visible in pass three unless something replaces it.
Cookies and sessions
A Cookie Manager keeps cookies across passes, so the user stays logged in, unless you clear them.
Connections
With KeepAlive on, the network connection from an earlier pass is reused, as a browser would do.
Cache entries
If a Cache Manager is present, files downloaded on earlier passes are remembered and may not be fetched again.
What starts fresh
Each pass starts with the first child again, with the pass index moved forward, and with any iteration-aware elements, such as CSV or Counter elements, advanced. Timers run again. Assertions run again. Result records are created again, and each sample is a new entry in the result file.
The stale value trap
A stale value is an old value that you wrongly keep using. Suppose an extractor fails on pass six, because the page changed. The variable still holds the value from pass five. The next request is sent with a number that was valid a moment ago, and perhaps no longer is. The test then shows odd errors that seem unrelated to the real cause. To avoid this, give the extractor a clear default text that signals failure, and add an assertion that checks the value is present before it is used.
Think of a whiteboard that is only partly wiped between lessons. A number written in the first lesson stays visible in the second unless someone rubs it out or writes over it. If the teacher forgets to write a new number, students read the old one and get confused. Variables in a loop behave like that whiteboard.
The state of each thread is private
Variables, cookies and counters belong to a single thread unless you ask for sharing. A shared Counter, or properties that every thread can read, can be used for shared state, but then threads can influence each other. Use sharing carefully, because it can make a test non-repeatable.
Place a Debug Sampler inside the loop for a single-user trial run, and read the variables on each pass. Seeing the values change with your own eyes is the fastest way to catch stale data.
PPerformance and Scalability Concerns
A loop can quietly turn a polite test into a hammer. These concerns explain how to keep your load realistic and your load generator healthy.
The tight loop problem
A tight loop is a loop with no pause. Each virtual user fires its next request the instant the last answer returns. A fast server answers in milliseconds, so one thread can send hundreds of requests per second. A hundred threads in tight loops can create tens of thousands of requests per second, far above what a hundred real people could ever produce. The server may fail, and the report will say the system cannot handle a hundred users, which is untrue. It could not handle a hundred robots with no manners.
Think time and pacing
Add timers so the pace per user resembles a real person. When you need a specific number of requests per second regardless of response time, use a throughput-shaping approach, such as the Constant Throughput Timer, which slows threads to hit a target rate. Together, these tools let you say “this loop creates about this many requests per second”, and then compare that to what your real traffic would be.
Load on the generator
Many samples
Every pass makes new samples. Heavy listeners that store them all will fill memory in long loops.
Frequent extraction
Extractors and assertions run on every pass, so costly patterns are costly many times over.
Large result files
Millions of samples create large files. Save only the fields you need.
Constant traffic
A tight loop can saturate the generator’s own network link before it stresses the server.
Infinite loops and time-bound tests
A loop count of infinite is common in soak tests, which run for hours to find slow problems such as memory leaks. An infinite loop never ends by itself, so you must give the test another way to stop. The Thread Group offers a scheduler with a duration, which ends the test after a set time. Always pair infinite loops with a duration, and always make sure the loop includes a sensible pause.
An infinite loop with no duration and no pause is the classic way to leave a test running over a weekend, hammering a shared environment. Always set a time limit before pressing start.
Scaling out
When one machine cannot generate enough load, JMeter can distribute the same plan across many machines. Each machine runs its own copy of every loop. If the plan says a hundred threads with ten passes, and you use five machines, you get five hundred threads and five thousand passes in total. Remember to divide thread counts by the number of machines when you plan the load.
SSafety, Security and Responsible Use
Loops make it very easy to generate a large amount of traffic and a large amount of data. Both can cause harm if handled carelessly.
Test only what you are allowed to test
Sending a flood of repeated requests to a system you do not own, or have no written permission to test, can disrupt that service and may be illegal. Always test systems you own, or where the owner has clearly agreed, preferably in a separate environment that mirrors production. Warn the people who operate the system before a heavy run, because unannounced repeated traffic looks exactly like an attack to security tools.
Loops that create data
A loop that places an order, creates an account or uploads a file creates real records every time. Ten thousand passes can leave ten thousand orders in a database. In a shared environment, that can fill storage, confuse other teams and trigger real emails or payments if the system is connected to live services. Plan how the test data will be cleaned up, use dedicated test accounts, and make sure external services such as email and payment gateways are replaced with safe stand-ins.
Use test accounts
Create special users with fake data and limited rights, never real customer details.
Plan cleanup
Have a script or process that removes test orders and files after the run.
Cap the totals
Decide the maximum records any loop may create and check the arithmetic before starting.
Protect secrets
Keep passwords and tokens out of the plan file and out of result files wherever possible.
Rate limits and blocking
Many systems protect themselves by limiting how many requests one user or address can send. A loop with no pauses, run from a single machine, can trigger that protection, and the server then answers with errors that have nothing to do with real capacity. Know whether such protection exists, and agree with the owners whether to relax it for the test environment.
Confirm three things in writing: you have permission, the totals are calculated and agreed, and a person knows how to stop the test quickly if something goes wrong.
MMonitoring, Logging and Debugging Loops
Loops can fail in quiet ways. A few simple habits let you see exactly what each pass did.
The debugging toolkit
View Results Tree
Shows each sample with its request and response. Use it with one user and a small loop count.
Debug Sampler
Prints the current variables so you can watch values change from pass to pass.
Response Assertion
Fails a sample when the response is not what was expected.
Log elements
A scripting element can write the pass number into the JMeter log when you need a precise trace.
Summary Listener
Shows how many samples each sampler produced, so you can compare with the arithmetic.
JMeter log file
Records warnings and errors from the tool itself, such as a loop count that could not be read as a number.
A reliable routine
Shrink the loop
Run one user, a loop count of two or three, and a single scenario pass.
Count the samples
Check that each sampler ran the number of times your arithmetic predicted.
Watch the variables
Use a Debug Sampler to confirm each pass gets new values, and that nothing stale is reused.
Test the exit
Force the exit condition and confirm the loop leaves when it should.
Scale up gradually
Raise users, then loop count, watching errors at each step.
Monitoring during a long loop
For tests that run for hours, watch both sides. On the load generator, watch processor use, memory and disk space, because a long loop produces a lot of data. On the server side, watch its own resources, queue lengths and error logs. A slow upward drift in response time across hundreds of passes often points to a leak or a growing queue. That kind of trend is exactly what looping soak tests are designed to find.
Run the final settings first in a small trial of a few minutes, and read the sample counts before starting the long run. If the numbers do not match the plan, fix them while it costs minutes, not hours.
RReading Reports from Looping Tests
When a sampler runs many times, your reports fill with repeated entries. Knowing how to read them keeps the story clear.
Names group the samples
Listeners and reports group samples by the name of the sampler. Every pass of a looped sampler has the same name, so all passes are merged into one row with a large sample count. This is usually what you want, because the average, the percentiles and the error rate then describe the sampler across all passes. A different pass number does not create a different row.
Should the pass number go in the name?
JMeter allows a variable in a sampler’s name, so it is possible to make “Search page 1”, “Search page 2” and so on. This is tempting but usually wrong for long loops. It creates one report row for every distinct name, which can balloon into thousands of rows and make the report unreadable. Use it only for very short loops where you truly want a separate row for each pass. For most tests, keep a single name and use the pass number only in the data you send.
Transactions give a business view
If the loop represents a business action such as “browse ten pages”, wrap the whole loop in a Transaction Controller to get one measured result for the entire browse, in addition to the individual samples. Teams then set targets on the business step, such as “browsing ten pages must finish within thirty seconds”, which is easier for non-technical readers to understand than a list of request times.
Beware of averages
With many passes, averages can hide trouble. A slow first pass, caused by cold caches, is diluted by many fast later passes. Percentiles, such as the 90th and 95th, show the unlucky end of the experience. If the first pass matters to real users, as it does for a first visit, consider measuring it separately by placing it outside the loop.
Do not compare a looping test with a non-looping test as if they were the same. Repeated requests may hit caches, reuse connections and warm up the system, which flatters the numbers. Compare like with like.
DDesign Patterns and Anti-patterns
Experienced engineers use a few reliable loop designs, and avoid a handful of tempting shortcuts that cause trouble later.
Patterns that work
Setup outside, repeat inside
Log in once before the loop, repeat only the activity that real users repeat, and log out after.
Count from a property
Read the loop count from a setting that can be changed on the command line, so one plan serves small and large runs.
Data per pass
Feed each pass from a data file or counter so requests differ.
Pause inside the loop
Add a timer so the pace matches human behaviour.
Early exit on a condition
Combine an If Controller with a break action so the loop ends when the story ends.
Transaction around the loop
Wrap the loop to report a business step, not only raw requests.
Anti-patterns to avoid
What people do
They put login inside the loop so every pass logs in again.
Why it hurts
The load on the login service becomes many times higher than real traffic, and the numbers describe a test that no real user behaves like.
Do this instead
Log in once outside the loop, or use a Once Only Controller, and repeat only the activity that really repeats.
What people do
They leave a tight loop with no pause and a very large count.
Why it hurts
The traffic is far beyond what real users produce. The server fails, and the test blames the wrong cause.
Do this instead
Add think time, or use a throughput timer to reach a specific, realistic request rate.
What people do
They send identical data on every pass.
Why it hurts
Caches answer repeated questions, and duplicate checks reject repeated actions, so the test measures shortcuts, not real work.
Do this instead
Vary the data on every pass with a data file, counter, or random function.
What people do
They nest loops without doing the arithmetic.
Why it hurts
Counts multiply, and the test sends many times more requests than planned, flooding the target and filling result files.
Do this instead
Multiply every count on paper, agree the total with the system owners, and confirm sample counts after a tiny trial.
BBest Practices and Common Mistakes
These are the habits that experienced performance engineers repeat on every project, and the slips that beginners make again and again.
Best practices checklist
| Area | Do this | Why |
|---|---|---|
| Naming | Give each Loop Controller a clear, simple name | Makes the plan readable, and the loop index variable depends on the name |
| Counts | Write the total request arithmetic before every run | Loop counts multiply, and surprises are costly |
| Setup | Keep login and setup outside the loop | Avoids unrealistic load on setup services |
| Pace | Add timers inside the loop | Prevents tight loops and unreal traffic |
| Data | Vary data on every pass | Avoids cache hits and duplicate rejections |
| Exit | Provide an early exit on failure or end of data | Real users stop, and so should the test |
| Limits | Use a duration with any infinite loop | Guarantees the test ends |
| Control | Read counts from properties | One plan serves both quick checks and full runs |
| Checking | Compare actual sample counts to the plan | Reveals silent early exits and mistakes |
Common mistakes
- Forgetting that the Thread Group also has a loop count, and so multiplying traffic by accident.
- Putting a Cookie Manager inside the loop, which can log the user out on every pass.
- Putting the CSV element in the wrong place, so rows are read at the wrong pace.
- Assuming the Once Only Controller means once per test, when it means once per start of the loop it lives in.
- Reading the pass index as one-based when it starts at zero.
- Using a Loop Controller where a While or ForEach Controller was needed.
- Leaving an infinite loop running with no duration and no pause.
- Putting the pass number into sampler names for a long loop, producing thousands of report rows.
- Trusting averages that blend a slow first pass with many fast later ones.
Run one user through one scenario pass with a loop count of two. Confirm the sample counts, the data on each pass, and the exit behaviour. Only then raise the numbers.
RReal-World and Industry Examples
Here is how teams use loops in different kinds of systems. These are illustrative patterns that show the scale and care involved, not descriptions of any company’s private tooling.
Online shopping: filling a cart
Large shopping platforms such as Amazon or Flipkart see customers who add several items to a cart before paying. A test models this with a Loop Controller around the “add to cart” request. The loop count comes from a property, say three for an ordinary basket and ten for a heavy one. A data file supplies a different product on each pass, and a short timer imitates the shopper choosing. Login stays outside the loop, and checkout happens once after it.
Search results pagination
A user who searches for a phone may read the first five pages of results. A Loop Controller of five passes repeats the “open next page” request, with a Counter element supplying the page number. If the search returns fewer pages than expected, an If Controller and a break action leave the loop early, exactly as a real user would stop when results run out.
Ride-hailing location updates
In a ride-hailing service such as Uber, a driver’s app sends location updates every few seconds while a trip is in progress. A test uses a Loop Controller to send a series of updates per virtual driver, with a timer of a few seconds between passes and a function that moves the position slightly each time. Thousands of simulated drivers produce a steady stream that tests the system’s ability to ingest continuous data.
Video streaming in chunks
Video services such as Netflix break a film into small chunks that the player fetches one after another. A test models a viewing session as a loop that requests the next chunk each pass, with a pause close to the length of the chunk. A long loop represents a long viewing session, and watching response times across many passes shows whether the service stays steady during a feature-length film.
Bulk upload of records
A bank or a government portal may accept a batch of records from a company in one go. A test uses a Loop Controller to submit a series of records, with unique references from a function, and a Counter to track how many were sent. A cap on the loop count protects the test database, and a cleanup process removes the created records afterwards.
What these examples share
In every case, the loop is a small part of a bigger design. Its power comes from the arrangement around it: setup outside, varied data inside, human pacing, early exits and arithmetic checked in advance.
TTrade-offs and Limits to Know
The Loop Controller is simple and reliable, and it has clear edges. Knowing them helps you choose the right tool.
Advantages
- Very easy to understand and to set up
- Keeps the plan short by avoiding copied samplers
- Count can come from a property or variable for flexible runs
- Works the same in single machine and distributed runs
- Exposes a pass index for building varied data
Disadvantages
- Counts only, with no built-in exit condition
- Multiplies traffic and data in ways that are easy to forget
- Repeated identical requests can flatter results through caching
- Nested loops can become hard to read and reason about
- Reports merge all passes unless names or transactions separate them
Closed model versus open model
A looping thread is a closed model. A fixed number of users each wait for an answer before the next request. If the server slows down, the users send fewer requests, and the pressure on the server falls, which can hide how bad things get. Real internet traffic is closer to an open model, where new users keep arriving at a certain rate whether or not the server is slow. To explore this, teams use throughput-controlling elements or special thread group plugins that fix the arrival rate. Knowing which model your loop creates helps you interpret the numbers correctly.
Coordinated omission in simple words
When a server stalls for ten seconds, a looping thread simply waits and sends nothing during that time. The long wait is recorded once, even though in real life many users would have arrived during the stall and suffered the delay. The resulting percentiles look better than reality. This effect is called coordinated omission. It does not mean loops are wrong. It means you should read the percentiles knowing how the load was generated, and complement closed loops with fixed-rate tests when tail latency matters.
Imagine a toll booth that jams for ten minutes. A test that sends one car at a time, and waits for each to pass, sees just one very slow car. Real traffic would have kept arriving and queued up by the hundreds. The single slow car understates the pain.
Choosing other tools when needed
If the repeat depends on a condition, use a While Controller. If it depends on a list, use a ForEach Controller. If the scenario itself must repeat for the whole user journey, use the Thread Group loop count or duration. If the load must arrive at a fixed rate, use a throughput timer or an arrival-rate thread group plugin. The Loop Controller is one tool among several, and a good design often uses more than one.
FFrequently Asked Questions
Short, direct answers to the questions people ask most often about the Loop Controller.
SSummary and Key Takeaways
The Loop Controller is a small element with a large effect. It decides how much work each virtual user performs, and so how much load your test creates.
Key Takeaways
- It repeats a section. The Loop Controller runs everything beneath it a set number of times, or forever if ticked Infinite, and sends nothing itself.
- Counts multiply. Threads, Thread Group passes and every nested loop multiply together, so always calculate the total before running.
- Know the two loops. The Thread Group repeats the whole scenario, and the Loop Controller repeats only one section, so keep setup steps outside it.
- Make each pass different. Use data files, counters, the zero-based pass index and random functions, and place the data element where it moves at the right pace.
- Pace and exit on purpose. Add think time to avoid tight loops, and use an If Controller with a break action, or a While Controller, when the story should end early.
- Read the results with care. Repeated requests can flatter numbers through caching, reports merge passes by name, and averages hide slow first passes.
- Be safe. Pair infinite loops with a duration, plan cleanup for created data, test only what you are allowed to test, and warn system owners before heavy runs.