A project manager I work with wanted a flow that waits until her director approves a project in a SharePoint list, then emails the team. There’s no trigger for “wait until this column changes” inside a running flow, so the flow has to check, wait, and check again. That’s exactly what the Do until loop is for.
Below I’ll explain how Do until runs, how to write its condition in basic and advanced mode, how to combine multiple conditions, what the Count and Timeout limits really are (PT1H, P30D and friends), how to read the iteration number, and the mistakes that cause endless loops or timeouts.
Quick answer: Add Control > Do until, set the Loop Until condition (for example varApproved is equal to true), and put the actions to repeat inside it, usually a Delay, a Get item and a Set variable. The actions run first and the condition is checked after each pass. The loop also stops at Count (default 60, max 5,000) or Timeout (default PT1H, ISO 8601).
What Do until does in Power Automate
Do until repeats a group of actions until a condition becomes true. It’s the “loop until” of cloud flows, and you’ll find it under the Control connector next to Condition, Switch and Apply to each. If you’re new to the building blocks, the Power Automate tutorials hub walks through them.
The detail that trips people up: Do until checks its condition after each pass, not before. Microsoft describes it as running all the actions in the loop first and then checking. So the body always runs at least once, even when the condition is already true when the flow reaches the loop.
The loop ends in one of three ways:
- The Loop Until condition evaluates to true.
- The loop reaches the Count limit (number of passes).
- The loop reaches the Timeout limit (total time).
If you need a true “while” loop that may run zero times, put a Condition in front of the Do until and only enter the loop when the work is actually needed.
Set the Do until condition: basic and advanced mode
Let’s start with a simple counter so you can see the mechanics. In an instant flow, initialize an integer variable named Number with the value 10.

Add Do until below it. In basic mode the condition has three parts, just like a Condition action: pick Number from dynamic content on the left, choose is equal to, and type 100 on the right.

Inside the loop, add a Compose that shows the current value, then an Increment variable action that adds 10 to Number. Without that increment, the condition can never become true.


Run the flow and the loop stops as soon as Number reaches 100. The run history shows one entry per pass, and you can page through them with the arrows on the Do until card.

Advanced mode lets you type the whole condition as an expression. Select Edit in advanced mode under Loop Until and enter it with a leading @. The basic condition above becomes:
@equals(variables('Number'), 100)
Use advanced mode when you need functions the basic builder can’t express, such as empty(), coalesce(), int() or a mix of and/or groups.
Multiple conditions with and() and or()
Do until accepts any expression that returns true or false, so and() and or() work as they do anywhere else. Both take two or more expressions. I go deeper into grouping in multiple conditions in Power Automate.
Here’s a real case. When someone uploads a file to a Project Documents library, the manager, Adele Vance, has to set Review Status (a Choice column) to Completed and add Reviewer Comments. The loop should keep reminding her until both are done:
@and(equals(outputs('Get_file_properties')?['body/ReviewStatus/Value'], 'Completed'), not(empty(coalesce(outputs('Get_file_properties')?['body/ReviewerComments'], ''))))

Two details matter. A Choice column is an object, so compare its Value. A blank comments column can arrive as null rather than an empty string, so empty(coalesce(x, '')) catches both. More blank-value patterns are in checking if a field is blank in Power Automate.
Inside the loop, the order is: Get file properties (so each pass reads fresh values), Send an email reminder, then Delay. The reminder body looks like this:
Hi Adele,
Please finish the review for @{triggerBody()?['{FilenameWithExtension}']}.
Set Review Status to Completed and add your reviewer comments.
Thanks,
Power Automate


For an “either” exit, use or(). This one stops when the item is approved or rejected, whichever happens first:
@or(equals(outputs('Get_item')?['body/Status/Value'], 'Approved'), equals(outputs('Get_item')?['body/Status/Value'], 'Rejected'))
After the loop, add the email to the file’s author confirming the review is done.

Do until Count and Timeout limits (PT1H, P30D)
Every Do until has two safety limits. In the new designer you’ll find them under Advanced parameters on the loop; in the classic designer, select Change limits.

| Setting | Default | Maximum | What it limits |
|---|---|---|---|
| Count | 60 | 5,000 | Number of passes through the loop |
| Timeout | PT1H (1 hour) | P30D in practice | Total time for all passes, in ISO 8601 |
Microsoft documents the 60 and 5,000 iteration numbers for Power Automate. For Timeout it documents the PT1H default, and the hard ceiling comes from the 30-day limit on any flow run, which is why P30D is the practical maximum. I’d avoid P1M, because a month isn’t a fixed number of days.
ISO 8601 durations start with P. Date units come before T and time units after it, all uppercase:
| Value | Means |
|---|---|
| PT5M | 5 minutes |
| PT1H | 1 hour (the default) |
| PT12H | 12 hours |
| P1D | 1 day |
| P7D | 7 days |
| P4DT4H4M | 4 days, 4 hours, 4 minutes |
| P30D | 30 days (the run limit) |
Two behaviors are worth knowing. First, Timeout is checked before each new pass, so a long action already running isn’t cut off; the next pass just doesn’t start.
Second, hitting Count or Timeout doesn’t fail the loop. If the last pass succeeded, Do until shows Succeeded and the flow carries on, even though your condition never became true. Add a Condition after the loop to check, and use try catch error handling with Scopes if you want the run to fail loudly.
I tested this with a document review loop limited to 3 passes. The review never finished, so the loop stopped at pass 3, and both the Do until and the flow still show Succeeded:

Get the current pass number with iterationIndexes()
You don’t always need a counter variable. The iterationIndexes() function returns the index of the current pass inside an Until loop, and it takes the loop’s internal name, which is its display name with spaces replaced by underscores:
Pass @{iterationIndexes('Do_until')} of the review check
The index starts at 0, so the first pass returns 0 and the third pass returns 2, as the run below shows. Wrap it in add(..., 1) if you want the count to start at 1 in emails or log entries.
If you rename the loop to “Wait for review”, the reference becomes iterationIndexes('Wait_for_review'). Microsoft documents it for Until loops, including nested ones.

I use it in reminder emails (“this is reminder 3”) and to escalate after a few passes. For an escalation that needs both a count and a status, a counter variable is easier to read. This condition stops after approval or after 12 checks:
@or(equals(outputs('Get_item')?['body/Status/Value'], 'Approved'), greaterOrEquals(variables('varChecks'), 12))
Real scenario: wait until a SharePoint item is approved
Back to the project manager’s request. The Project Approvals list has an Is Approved Yes/No column that starts as No (an empty box in the list view). When a project is added, the flow should wait until the director sets Is Approved to Yes, then email the project owner.

Start with When an item is created on the list, then add a Boolean variable named varApproved set to false.

Add Do until with the condition varApproved is equal to true and set Count to 10 for testing. In advanced mode the condition is:
@equals(variables('varApproved'), true)

Inside the loop, add a Delay first. In production I use 15 minutes to an hour; for testing, a few seconds is fine. Then get the SharePoint item by the trigger’s ID so every pass reads the latest value.

Add a Condition that checks Is Approved is equal to true. In the True branch, set varApproved to true and send the email.



Create an item, then change Is Approved to Yes a few minutes later. Here the director approved Customer Portal Upgrade on 10/14/2026, and the next pass picked it up:

The run history shows how many passes it took before the condition was met.

If you only need someone to approve something, though, you don’t need a loop. Start and wait for an approval already waits for the response, and handling approval timeout in Power Automate covers the 30-day limit.
Do until vs Apply to each
| Do until | Apply to each | |
|---|---|---|
| Runs | Until a condition is true | Once per item in an array |
| Number of passes | Unknown up front, capped by Count (max 5,000) | Fixed by the array length |
| Minimum passes | At least 1 | 0 if the array is empty |
| Runs in parallel | No, one pass at a time | Optional, concurrency up to 50 |
| Typical use | Polling, waiting for a status, paging | Processing list items, files, rows |
Rule of thumb: if you already have the items, use Apply to each. If you’re waiting for something to change, or you don’t know how many passes you’ll need, use Do until. If two things should happen at the same time instead, look at parallel branches in Power Automate.
Common Do until mistakes and how to fix them
- No Delay inside the loop. Without one, the loop burns through all 60 passes in seconds and every pass counts against your daily request limits. Always pause between checks when you’re polling.
- The value is never refreshed. If Get item or Get file properties sits before the loop, the condition keeps testing the same old value. Move the read inside the loop.
- The variable isn’t updated inside the loop. A condition on varApproved needs a Set variable (or Increment variable) inside the loop, or it can never become true.
- Type mismatch. Comparing a Choice column object with ‘Approved’, a Yes/No column with the text ‘true’, or a text number with 100 never matches. Use [‘Value’] for Choice, enter
trueas an expression, and convert text withint(). - equals() overshoots. If a counter jumps from 95 to 105,
equals(x, 100)is never true. UsegreaterOrEquals()for counters. - Timeout too short. With the PT1H default and a 15-minute Delay, you get about four checks. Raise Timeout to PT12H or P7D when people need time to respond.
- Assuming a limit means failure. When Count or Timeout ends the loop, it still shows Succeeded. Check the status after the loop.
- An approval inside the loop. Every pass sends a new approval request. Send it once before the loop, or skip the loop entirely.
When a run does fail, it helps to get alerted quickly. I set that up with an email with the failed flow run link. And if the flow shouldn’t start for every item in the first place, trigger conditions in Power Automate keep it from running at all.
If you’re building approval and waiting logic into your flows, these step-by-step guides are good next reads:
Frequently Asked Questions
Does Do until run at least once in Power Automate?
Yes. Do until runs the actions inside the loop first and checks the condition after each pass, so the body always runs once. Put a Condition before the loop if it shouldn’t run when the condition is already true.
What is the maximum Count for a Power Automate Do until loop?
The default is 60 passes and the maximum is 5,000. If you need more, split the work into several runs or use a child flow.
What does PT1H mean in a Do until timeout?
PT1H is an ISO 8601 duration for 1 hour and is the default Timeout. P starts the duration, T separates date units from time units, and H means hours. PT30M is 30 minutes and P7D is 7 days.
Can a Do until loop run for 30 days?
Yes, set Timeout to P30D and give it enough Count passes with a Delay inside. A flow run can’t last longer than 30 days, so that’s the practical ceiling.
How do I add multiple conditions to a Do until loop?
Select Edit in advanced mode and combine expressions with and() or or(), for example @and(equals(a, 1), equals(b, 2)). Microsoft lists the current loop limits on the Power Automate limits and configuration page.

Hey! I’m Bijay Kumar, founder of SPGuides.com and a Microsoft Business Applications MVP (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and training videos. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.