Skip to main content
Version: 1.28 (Current)

Execute Actions for each List Entry

Audience: Low-code Engineers

Skill Prerequisites: Actions, Lists, Tokens

Runs a list of actions once for each entry in a list, like a for each loop. You can loop over all the entries, or only the ones that match a filter.

Inside the loop, each property of the current entry is a token named after the list: [<ListName>:<Property>], for example [ContactsList:Email]. The position of the current entry is in [<ListName>:$Index], starting at 0.

The list comes from an earlier action, such as Create List from SQL, Create List from JSON, Create List from a CSV source, Create List from Excel (.xlsx) or Add List Entry. In a listing, it can also be the listing's rows.

Typical Use Cases​

  • Send a personalized email to each contact in a list
  • Call an API or a workflow once for each order returned by a query
  • Update each row of a listing, for example after the user selects rows and clicks a button
  • Check each entry and collect the ones that fail a rule, with Add List Entry
  • Give every entry a new property, such as a calculated value, with Extend List Properties

Don't use it to​

Action NameDescription
Create List from SQLCreates a list from the rows of a query.
Create List from JSONCreates a list from a JSON array.
Create List from a CSV sourceCreates a list from CSV text or a CSV file.
Create List from Excel (.xlsx)Creates a list from an Excel sheet.
Add List EntryAdds one entry to a list, for example to collect results inside the loop.
Extend List PropertiesAdds or changes a property of the current entry, when used inside the loop.
Paginate ListKeeps only one page of a list, for example to process a large list in batches.
RepeatRuns actions a number of times, or while a condition is true.
Execute ActionsRuns actions once, with error handling. Useful inside the loop to handle an error for one step.

Input Parameter Reference​

ParameterDescriptionSupports TokensDefaultRequired
List NameThe name of the list to loop over, for example ContactsList. List names are case-sensitive. If it's empty, the default list of the current context is used, for example the rows of a listing. If the list doesn't exist, the action fails.Yesempty stringYes
FiltersLoops only over the entries that match. Each row has a Field, which is a property name, for example Status, and a Value, for example Active. An entry must equal every value to be included. See Filters.Yes (values)emptyNo
Context BehaviorWhat happens to tokens created or changed during each iteration. See Context behavior.NoUpdate all tokens in the original contextNo
Action ListThe actions to run for each entry. They can use the entry tokens.NoemptyNo
Continue on errorWhen checked, a failed iteration doesn't stop the loop. The On Error actions run, then the loop moves on to the next entry. When unchecked, a failed iteration ends the loop.NofalseNo
On ErrorActions to run when an iteration fails. See How errors are handled.NoemptyNo

Entry tokens​

At the start of each iteration, these tokens are created from the current entry:

TokenValue
[<ListName>:<Property>]The value of each property of the entry, for example [ContactsList:Email].
[<ListName>:$Index]The position of the entry, starting at 0. With filters, it counts only the matching entries.
[<ListName>:$EntityIndex]The same as $Index. It's kept for older applications.

A few things to know:

  • <ListName> is the list name as it was resolved, for example ContactsList. Token names aren't case-sensitive, so [contactslist:email] also works.
  • Property names can contain colons or dots. For example, a Dynamics lookup gives [ContactsList:ParentAccount:Id], and a nested JSON property gives [OrdersList:customer.email].
  • For lists created from JSON, [<ListName>] holds the whole entry as JSON, and each nested object or array property holds its JSON, for example [OrdersList:lines]. See Create List from JSON.
  • The tokens are copies taken at the start of the iteration. If an action in the loop adds a property with Extend List Properties, there's no token for it until the next time the list is looped over.
  • A token that already has the same name as a property is replaced during the loop. For example, a [ContactsList:Email] token created earlier is overwritten by each entry's value.
  • There's no token for the total number of entries. Create List from JSON creates a [<ListName>:Count] token that you can use.

Inside the loop, you can also use every token that existed before the loop, including the entry tokens of an enclosing loop.

In a listing, when List Name is empty, the rows are in a list named ActionGridEntry, so the tokens are [ActionGridEntry:<FieldName>], using the names of the listing's fields.

Filters​

  • Filter values support tokens. They're resolved once, before the loop starts.
  • Field names don't support tokens.
  • The comparison is an exact match and is case-sensitive. active doesn't match Active.
  • Entries that don't have the property never match.
  • Values from Create List from SQL or Create List from Excel (.xlsx) keep their data type. Numbers and dates never match, because the filter value is text. Convert the column to text in the query, for example CAST(Id AS nvarchar(20)) AS Id, or use a condition on the actions inside the loop instead.
  • For anything other than "equals", put a condition on the actions inside the loop, for example [OrdersList:Status] != "Cancelled".

Context behavior​

Each iteration runs on a copy of the tokens. Context Behavior decides what's copied back to the original tokens after each iteration. The next iteration and the actions after the loop read from the original tokens.

OptionWhat's copied back after each iterationUse it when
Update all tokens in the original context (default)Every token created or changed in the iteration, including the entry tokens.The next iteration or the actions after the loop need values from the loop.
Don't save the iteration tokensNothing. Every iteration starts from the tokens as they were before the loop.Each iteration is independent. This is also the fastest option for large lists.
Update the tokens in the initial contextOnly tokens that already existed before the loop. New tokens are discarded.You want to carry specific values, such as a running total, without leaking other tokens. Create those tokens with an initial value before the loop.

$Index and $EntityIndex are never copied back. Tokens from an iteration that failed aren't copied back either.

caution

With Update all tokens in the original context, the entry tokens of the last entry stay after the loop. Also, if an entry doesn't have a property, for example in a list created from JSON where some objects miss a field, its token keeps the previous entry's value. Use Don't save the iteration tokens when entries can have different properties, or check the values carefully.

Lists, objects and users​

Context Behavior only applies to tokens. Lists and objects are shared with the rest of the actions:

  • Entries you add with Add List Entry, properties you set with Extend List Properties, and lists or objects you create inside the loop are kept after the loop, whatever option you choose.
  • Entries added to the list you're looping over aren't included in the current loop.
  • Setting a token named like an entry token, for example with Create/Update Tokens and the name OrdersList:Status, also changes that property of the current entry.

Users loaded with Load User or Load Users from SQL inside the loop are only kept until the loop ends. After the loop, the current user and the list of users go back to what they were before it.

How errors are handled​

An iteration fails when one of its actions raises an error, for example a failing query or Throw Exception.

Continue on errorOn ErrorWhat happens when an iteration fails
UncheckedemptyThe loop ends and the error is passed up. Administrators and low-code engineers see Failed to execute actions on list item <index>., other users see a generic error.
Uncheckedhas actionsThe On Error actions run. If one of them ends execution, for example Display Message, execution ends there. Otherwise the loop ends and the error is passed up.
CheckedanyThe On Error actions run and the loop continues with the next entry. Messages, redirects and other results from On Error are ignored.

The On Error actions run with the tokens of the failed iteration, so they can use the entry tokens, for example [ContactsList:Email]. They also get these tokens:

TokenValue
[ExceptionMessage]Failed to execute actions on list item <index>., where <index> is the $Index of the failed entry.
[Exception]The messages of the error and of all its causes, one per line. The original error message is here, for example the Admin Message of Throw Exception.
[ExceptionType]The type of the error.
[ExceptionStack]The technical stack trace.

When the error is passed up, the On Error actions of an enclosing Execute Actions can catch it. To handle an error for one step without failing the iteration, put that step in an Execute Actions inside the loop.

Stopping the loop​

There's no action that leaves only the loop. Any action that ends execution ends the loop and all remaining actions:

Nested lists​

You can put an Execute Actions for each List Entry inside another one. The inner loop can use the entry tokens of both lists, for example [OrdersList:OrderId] and [LinesList:ProductId]. Use a different list name for each loop.

A list entry can't hold another list that you can loop over directly. For a list created from JSON, create a child list for each entry: inside the loop, add Create List from JSON with [OrdersList:lines] as the JSON Model, then loop over the child list. See example 3.

Considerations​

  • Create the list first. The action fails with No entity with this Entity Name: <name> if the list doesn't exist. An empty list is fine: the actions just don't run.
  • Performance. Each iteration copies all the tokens, and with the default Context Behavior copies them back. Loops over thousands of entries, or with many tokens, can be slow. Use Don't save the iteration tokens when you can, keep the actions inside the loop few, and prefer list actions that work on the whole list, such as Import List into Database.
  • Long loops hold up the request. In forms and listings, keep lists small, or run the loop in Execute Actions Asynchronously.
  • Conditions. Token values are placed in quotes, so compare with quoted strings, for example [ContactsList:Status] == "Active".
  • SQL inside the loop. Pass entry values to Run SQL Query with Bind Tokens, not by pasting tokens into the query.

Examples​

tip

To understand how to use the below examples, please see Running Examples.

1. Mark each active contact as notified​

This action goes through the entries of ContactsList whose Status is Active. For each one, it updates a table row, using bind tokens for the entry's values. The tokens from each iteration aren't needed afterwards, so they aren't saved.

{
"Title": "Execute Actions for each List Entry",
"ActionType": "ExecuteActionsOnEntityList",
"Description": "Mark active contacts as notified",
"Parameters": {
"EntityName": "ContactsList",
"Filters": [
{
"name": "Status",
"value": "Active"
}
],
"ContextBehavior": {
"Expression": "",
"Value": "NoPreserve",
"IsExpression": false,
"Parameters": {}
},
"ActionList": [
{
"Title": "Run SQL Query",
"ActionType": "RunSql",
"Description": "Mark the contact",
"Parameters": {
"SqlQuery": "UPDATE Contacts SET NotifiedOn = GETDATE() WHERE ContactId = @ContactId",
"BindTokens": [
{
"name": "ContactId",
"value": "[ContactsList:ContactId]"
}
]
}
}
],
"ContinueOnError": false,
"OnError": []
}
}

2. Keep going when one entry fails​

This action calls a stored procedure for each order in OrdersList. If one call fails, the error is logged with the order ID and the original message, and the loop moves on to the next order.

{
"Title": "Execute Actions for each List Entry",
"ActionType": "ExecuteActionsOnEntityList",
"Description": "Process each order",
"Parameters": {
"EntityName": "OrdersList",
"Filters": [],
"ContextBehavior": {
"Expression": "",
"Value": "NoPreserve",
"IsExpression": false,
"Parameters": {}
},
"ActionList": [
{
"Title": "Run SQL Query",
"ActionType": "RunSql",
"Description": "Process the order",
"Parameters": {
"SqlQuery": "EXEC dbo.ProcessOrder @OrderId",
"BindTokens": [
{
"name": "OrderId",
"value": "[OrdersList:OrderId]"
}
]
}
}
],
"ContinueOnError": true,
"OnError": [
{
"Title": "Log Error",
"ActionType": "LogError",
"Description": "Log the failed order",
"Parameters": {
"Message": "Order [OrdersList:OrderId] (entry [OrdersList:$Index]) failed: [Exception]"
}
}
]
}
}

3. Loop over nested JSON arrays​

OrdersList was created with Create List from JSON from orders that each have a lines array. For each order, this action turns [OrdersList:lines] into a LinesList list, then runs a query for each line. The inner loop uses tokens from both lists.

{
"Title": "Execute Actions for each List Entry",
"ActionType": "ExecuteActionsOnEntityList",
"Description": "Save the lines of each order",
"Parameters": {
"EntityName": "OrdersList",
"Filters": [],
"ContextBehavior": {
"Expression": "",
"Value": "NoPreserve",
"IsExpression": false,
"Parameters": {}
},
"ActionList": [
{
"Title": "Create List from JSON",
"ActionType": "LoadEntitiesFromJson",
"Description": "Turn the order lines into a list",
"Parameters": {
"JsonModel": "[OrdersList:lines]",
"EntityName": "LinesList",
"OnError": []
}
},
{
"Title": "Execute Actions for each List Entry",
"ActionType": "ExecuteActionsOnEntityList",
"Description": "Save each line",
"Parameters": {
"EntityName": "LinesList",
"Filters": [],
"ContextBehavior": {
"Expression": "",
"Value": "NoPreserve",
"IsExpression": false,
"Parameters": {}
},
"ActionList": [
{
"Title": "Run SQL Query",
"ActionType": "RunSql",
"Description": "Insert the line",
"Parameters": {
"SqlQuery": "INSERT INTO OrderLines (OrderId, Sku, Quantity) VALUES (@OrderId, @Sku, @Quantity)",
"BindTokens": [
{
"name": "OrderId",
"value": "[OrdersList:id]"
},
{
"name": "Sku",
"value": "[LinesList:sku]"
},
{
"name": "Quantity",
"value": "[LinesList:quantity]"
}
]
}
}
],
"ContinueOnError": false,
"OnError": []
}
}
],
"ContinueOnError": false,
"OnError": []
}
}

4. Collect the entries that fail a rule​

This action checks each entry of ContactsList and adds the ones without an email to a new MissingEmailList list. The new list is kept after the loop, so you can export it or show it afterwards.

{
"Title": "Execute Actions for each List Entry",
"ActionType": "ExecuteActionsOnEntityList",
"Description": "Find contacts without an email",
"Parameters": {
"EntityName": "ContactsList",
"Filters": [],
"ContextBehavior": {
"Expression": "",
"Value": "NoPreserve",
"IsExpression": false,
"Parameters": {}
},
"ActionList": [
{
"Title": "Add List Entry",
"ActionType": "CreateEntity",
"Description": "Remember the contact",
"Condition": "[ContactsList:Email] == \"\"",
"Parameters": {
"EntityName": "MissingEmailList",
"EntityProps": [
{
"name": "ContactId",
"value": "[ContactsList:ContactId]"
},
{
"name": "Name",
"value": "[ContactsList:Name]"
}
]
}
}
],
"ContinueOnError": false,
"OnError": []
}
}

Revised 09/27/2026