Guides / Repeat a task for each item
Verified against Flow 5.0.0-beta.39
A for-each task runs one task once for every item in a list, in parallel, inside the same run. Use it to deploy to several regions, process each file in a batch, or call a service once per record. This guide is for workflow authors.
The task stays one node on the canvas. When the run reaches it, Flow resolves its items to an array and creates one task run per item, named <task name>[<index>] with the index counted from 0. Items run in parallel, as fast as dispatchers claim them, and share the run workspace.
Inside each item, $(params.item) is the current item and $(params.index) its position. The task succeeds when every item succeeds.
Only tasks that run as a container can repeat: catalogue and workspace tasks, Execute Shell, Run Python Script, Run Custom Task, the AI tasks, Upload Artifact and Download Artifact. Switches, approvals, waits, locks and Run Workflow can't.
This example deploys to three regions. The region list is a workflow parameter, so each run can change it.
In the editor, open the Parameters tab and select Add parameter.
Enter the Name regions, leave Type as Text, and enter the Default value (optional) ["sydney","london","virginia"].
Select Add.
Open the Canvas tab. In Add a task, the Workflow category is open: drag For each onto the canvas.
Repeat a task for each item opens.
In Task, choose Execute Shell.
In Items, enter $(params.regions).
In Task name, enter deploy. Flow fills in the task's display name until you type your own.
Select Next: task parameters.
The task's own form, Edit Execute Shell, opens.
Select the Shell Script field. In Update Shell Script, enter:
echo "Deploying item $(params.index) to $(params.item)"Select Update, then Apply.
The node shows a purple For each badge and is drawn as a stack of cards.
Drag a link from Start to deploy, and from deploy to End.
On the Workflows page, select Run it on the workflow's card, then Run and View.
The run page opens. When the run ends, the deploy node's badge reads For each · 3 of 3 succeeded and the run's status is Succeeded.

To turn for-each on for a task that's already on the canvas, open its form, select the Configure tab and turn on Run for each item, then enter the Items. The tab shows a purple For each tag while it's on. Turning it off makes the task an ordinary one again.
Items takes a JSON array, or a single reference whose value is an array or text holding one.
| Items | Example | Checked |
|---|---|---|
| A JSON array | ["sydney","london","virginia"] |
When you save the version |
| A parameter | $(params.regions) |
When the run reaches the task |
| An earlier task's result | $(tasks.list-regions.results.regions) |
When the run reaches the task |
Anything else shows Enter a JSON array or a single reference such as $(params.items), and Next: task parameters and Apply stay disabled.
An item can be text, a number, an object or an array. An object or array reaches the task as JSON text, and $(params.index) is always text. A container reads the same values as the environment variables PARAM_ITEM and PARAM_INDEX.
Two names are reserved:
item or index parameter can't run for each item. Saving refuses it.[ and a number ], such as deploy[2], because item names take that form. The form shows Task names cannot end in [ and a number ]; that form is reserved for for-each items. Other brackets, such as Deploy [prod], are allowed.The run page groups every item under its task:
<succeeded> of <total> succeeded. It reads For each · 0 items when the array was empty.3 items · 3 succeeded, adding · 1 running or · 1 failed while either isn't zero. The task itself runs nothing, so it has no View Log.[0], the item, its status, the failure reason, its duration, the attempt from the second one on, and its own View Log.All 3 items succeeded. or, for example, 1 of 3 items did not succeed.
After the task, $(tasks.<name>.results.<result>) is an array in item order, with null for an item that didn't succeed. For example, if deploy declared a result url and the second item failed, a later task reading $(tasks.deploy.results.url) gets:
["https://sydney.example.com", null, "https://virginia.example.com"]A task that declares no results collects each result its items produced into such an array. An empty array of items succeeds at once, with empty arrays as its results.
Each item's results are capped like any task's: 4096 bytes on Flow's Kubernetes dispatcher. If the combined arrays pass MongoDB's 16 MB document limit, the task fails with ResultsTooLarge and keeps no results.
Any item that doesn't succeed fails the whole task, with the reason ItemFailed. The other items still finish.
ForeachTooManyItems, and no item runs.ForeachItemsInvalid.Insights counts a for-each task's items under the task's name, and its Task runs panel can group by For-each item. See Insights.
ParamUnresolved?$(params.x) and $(tasks.t.results.r) resolve.