Study guide

7.1 For Each Scope: Payload Iteration, Batch Size & Streaming Data

Salesforce Certified MuleSoft Developer I Exam

Track your progress as you read

Finished sections get a check mark.

1 Chapter 1: Creating Application Networks & API-Led Connectivity

1.1 The IT Delivery Gap & API-Led Connectivity Architecture 1.2 Application Network Foundations & Center for Enablement (C4E) 1.3 Anypoint Platform Architecture & Core Components

2 Chapter 2: Designing APIs with RAML & API Designer

2.1 RAML 1.0 Fundamentals, Data Types & Resource Hierarchy 2.2 Reusable API Fragments, ResourceTypes & Traits 2.3 API Mocking Service, Documentation & Anypoint Exchange Publishing

3 Chapter 3: Accessing and Modifying Mule Events

3.1 Mule 4 Event Architecture: Message, Payload, Attributes & Variables 3.2 Flow Variable Management & Target Variables Pattern 3.3 Accessing Event Metadata, Inbound Attributes & Context Properties

4 Chapter 4: Structuring Mule Applications

4.1 Modular Flow Composition: Flows, Subflows & Private Flows 4.2 Configuration Property Files & Environment Management 4.3 Secure Properties Tool, Encryption & Maven Project Packaging

5 Chapter 5: Building API Implementation Interfaces

5.1 APIkit Scaffolding, Router Configuration & Interface Generation 5.2 HTTP Listener Configuration, Path Matching & Query/URI Parameters 5.3 Interface vs. Implementation Separation & Backend Flow Wiring

6 Chapter 6: Using Connectors & External Systems

6.1 Database Connector: Select, Insert, Update, Stored Procedures & Watermarking 6.2 HTTP Request Connector: Headers, Query Params, Response Timeouts & Target Variables 6.3 Salesforce Connector, JMS Messaging & File/FTP Connectors

7 Chapter 7: Processing Records & Batch Integration

7.1 For Each Scope: Payload Iteration, Batch Size & Streaming Data 7.2 Batch Job Architecture: Input, Process, and Complete Phases 7.3 Batch Step Accept Expression, Failure Handling & Batch Aggregator 7.4 Object Store: Persisting Data Between Flow Executions

8 Chapter 8: Transforming Data with DataWeave 2.0

8.1 DataWeave 2.0 Syntax, Type System & Selectors 8.2 Core Functions: map, filter, pluck, reduce, groupBy & orderBy 8.3 Custom Functions, Format Transformations & Type Coercion 8.4 Calling Mule Flows from DataWeave & Reusing DataWeave Modules

9 Chapter 9: Routing Events & Flow Control

9.1 Choice Router: Conditional Expressions & Default Routing 9.2 Scatter-Gather Router: Parallel Execution, Aggregation & Error Traps 9.3 Async Scope, Round Robin & First Successful Routing 9.4 Validating Mule Events with the Validation Module

10 Chapter 10: Handling Errors & Exception Management

10.1 Mule 4 Error Object Hierarchy & Custom Error Types 10.2 On-Error Continue vs. On-Error Propagate Mechanisms 10.3 Try Scope Exception Isolation & Global Error Handling Strategies

11 Chapter 11: Debugging and Troubleshooting Mule Applications

11.1 Logger Configuration, Categories & Thread/Context Diagnostics 11.2 Anypoint Studio Debugger: Breakpoints, Expression Watches & Step-Through 11.3 MUnit 2.x Testing: Unit Tests, Mocking Connectors & Assertions

12 Chapter 12: Deploying and Managing APIs and Integrations

12.1 CloudHub 1.0 & 2.0 Architecture: Workers, vCores & Clustering 12.2 Runtime Manager: Application Management, Alerts, Insights & Logs 12.3 API Manager: Auto-Discovery, API Gateway, SLA Tiers & Standard Policies

7.1 For Each Scope: Payload Iteration, Batch Size & Streaming Data

Key Takeaways Explain This Topic AI

The For Each scope (<foreach>) processes collections sequentially on the calling thread, executing child message processors once per item (or chunk of items if batchSize > 1).

Upon exiting the For Each scope, the original root payload that existed prior to entering the scope is automatically restored, but any flow variables modified or created inside the scope persist with their accumulated state.

The scope provides a built-in, 1-indexed vars.counter tracking the current iteration index, and allows custom collection extraction via the collection attribute (defaulting to #[payload]).

If an unhandled exception occurs inside a For Each iteration, iteration immediately aborts, remaining items in the collection are discarded, and execution routes to the enclosing flow's error handler.

Unlike Parallel For Each (which splits execution across multiple threads and returns an aggregated result) or Batch Job (which processes asynchronously in persistent queues), For Each is synchronous, sequential, and lightweight.

Last updated: August 2026

For Each Scope: Payload Iteration, Batch Size & Streaming Data

In enterprise application integration, processing collections of records—such as arrays of purchase orders, lists of customer database rows, or parsed CSV lines—is a daily requirement. Mule 4 provides multiple mechanisms to iterate over and transform collections. The For Each scope ( <foreach> ) is the foundational, lightweight component for sequential collection processing within a synchronous flow execution context.

Understanding how <foreach> splits payloads, manages variable state, handles runtime exceptions, and preserves the original message payload is essential for developing reliable integration flows and passing the Salesforce Certified MuleSoft Developer I exam.

1. For Each Scope Architecture & Execution Model

The For Each scope splits any iterable collection (Java List , Array , Map , ResultSet , or streaming CursorProvider ) into individual elements and executes its child message processors sequentially for each item. +-----------------------------------------------------------------------------------------+

  • | FOR EACH SCOPE EXECUTION MODEL |
  • | |
  • | Inbound Payload: [ "Order-A", "Order-B", "Order-C" ] |
  • | Inbound Variables: { totalOrders: 0, processedCount: 0 } |
  • | | |
  • | v |
  • | +---------------------------------------------------------------------------------+ |
  • | | <foreach> Scope (Sequential Iteration on Calling Thread) | |
  • | | | |
  • | | Iteration 1: | |
  • | | - payload = "Order-A" | |
  • | | - vars.counter = 1 | |
  • | | - vars.processedCount updated to 1 | |
  • | | | |
  • | | Iteration 2: | |
  • | | - payload = "Order-B" | |
  • | | - vars.counter = 2 | |
  • | | - vars.processedCount updated to 2 | |
  • | | | |
  • | | Iteration 3: | |
  • | | - payload = "Order-C" | |
  • | | - vars.counter = 3 | |
  • | | - vars.processedCount updated to 3 | |
  • | +---------------------------------------------------------------------------------+ |
  • | | |
  • | v |
  • | Outbound Payload: [ "Order-A", "Order-B", "Order-C" ] <--- RESTORED ORIGINAL! |
  • | Outbound Variables: { totalOrders: 0, processedCount: 3 } <--- MODIFICATIONS PERSIST! |
  • +-----------------------------------------------------------------------------------------+

Key Architectural Principles:

Single-Threaded & Synchronous: The For Each scope executes on the calling thread. It does not spawn background worker threads. Iteration N+1 never begins until iteration N has fully completed all message processors inside the scope.

Payload Splitting: During each iteration, the payload is temporarily replaced with the single element being processed (or an array of elements if batchSize > 1 ).

Root Payload Restoration: When all iterations finish successfully, the Mule runtime discards the output of the final iteration and restores the original inbound payload that existed prior to entering the <foreach> scope.

Variable Mutation Persistence: Any flow variables ( vars ) created or modified inside the <foreach> scope persist across iterations and remain in the Mule event after exiting the scope .

2. Core Configuration Attributes

The <foreach> scope XML element provides four key attributes that control iteration behavior:

Attribute Type Default Value Description

collection DataWeave Expression #[payload] Expression defining the collection to iterate over. Can target nested collections (e.g., #[payload.orders] ).

batchSize Integer 1 Number of records grouped together in each iteration. When set to N > 1 , payload inside the scope is a sub-array of N items.

rootMessageVariableName String rootMessage Variable name storing the original root Mule message during iteration. Accessible inside the scope via vars.rootMessage .

counterVariableName String counter Name of the variable tracking iteration count. Accessible inside the scope as vars.counter (1-indexed).

  • XML Blueprint: Basic Iteration with Custom Collection <flow name="process-invoices-flow">
  • <http:listener config-ref="HTTP_Listener_config" path="/invoices" doc:name="Listener" />
  • <!-- Inbound payload is a JSON Object: { "batchId": "B-101", "items": [ {...}, {...} ] } -->
  • <set-variable variableName="totalProcessed" value="#[0]" doc:name="Init Counter" />
  • <set-variable variableName="failedIds" value="#[[]]" doc:name="Init Failed Array" />

<!-- Iterate specifically over payload.items -->

<foreach collection="#[payload.items]" counterVariableName="idx" rootMessageVariableName="originalOrder" doc:name="For Each Invoice">

  • <!-- Inside scope: payload is a single item from items array -->
  • <logger level="INFO"

message="#['Processing item ' ++ vars.idx ++ ' of batch ' ++ vars.originalOrder.payload.batchId ++ ' with ID: ' ++ payload.invoiceId]" />

  • <!-- Outbound HTTP Call to Billing API -->
  • <http:request method="POST" config-ref="Billing_HTTP_Config" path="/process">
  • <http:body><![CDATA[#[payload]]]></http:body>
  • </http:request>
  • <!-- Accumulate variable -->
  • <set-variable variableName="totalProcessed" value="#[vars.totalProcessed + 1]" doc:name="Increment" />
  • </foreach>
  • <!-- AFTER FOR EACH: -->
  • <!-- payload is restored to: { "batchId": "B-101", "items": [ ... ] } -->
  • <!-- vars.totalProcessed contains the final count -->
  • <logger level="INFO" message="#['Completed processing. Total items: ' ++ vars.totalProcessed]" />
  • </flow>
  • 3. The batchSize Attribute (Chunking Records)

By default, batchSize="1" , meaning child message processors execute once per individual element. However, when interfacing with external bulk endpoints (such as database bulk inserts or batch REST endpoints), processing records in chunks of 50, 100, or 500 is far more performant than individual network round-trips.

When batchSize is set to N > 1 :

The runtime groups the source collection into sub-arrays of up to N elements.

Inside the <foreach> scope, payload is an Array containing up to N items .

vars.counter increments by 1 for each chunk/sub-array , not for each individual item.

The final chunk may contain fewer than N items if the collection length is not evenly divisible by batchSize . +-----------------------------------------------------------------------------------------+

  • | BATCH SIZE CHUNKING (batchSize = 2) |
  • | |
  • | Inbound Collection: [ "A", "B", "C", "D", "E" ] (5 items) |
  • | |
  • | Iteration 1 (vars.counter = 1): payload = [ "A", "B" ] (size = 2) |
  • | Iteration 2 (vars.counter = 2): payload = [ "C", "D" ] (size = 2) |
  • | Iteration 3 (vars.counter = 3): payload = [ "E" ] (size = 1) |
  • | |
  • | Total Iterations: 3 |
  • +-----------------------------------------------------------------------------------------+

XML Configuration: Chunked Database Bulk Insert <foreach collection="#[payload]" batchSize="100" doc:name="For Each Chunk of 100">

  • <!-- payload is an Array of up to 100 records -->
  • <db:bulk-insert config-ref="Database_Config" doc:name="Bulk Insert Chunk">
  • <db:sql><![CDATA[
  • INSERT INTO staging_accounts (account_id, name, status)
  • VALUES (:accountId, :name, :status)
  • ]]></db:sql>
  • </db:bulk-insert>

<logger level="INFO" message="#['Inserted chunk #' ++ vars.counter ++ ' with records: ' ++ sizeOf(payload)]" />

  • </foreach>
  • 4. Error Handling in For Each: Sequential Fail-Fast Semantics

A critical concept tested on the certification exam is how runtime errors behave inside <foreach> .

Default Behavior: Immediate Halt (Fail-Fast)

If an unhandled exception occurs during any iteration:

The <foreach> scope immediately halts execution .

All remaining, unprocessed items in the collection are discarded and never executed.

The exception is routed directly to the enclosing flow's error handler (or global error handler).

Any variable mutations completed during earlier successful iterations are retained in the flow context . +-----------------------------------------------------------------------------------------+

  • | FOR EACH UNHANDLED ERROR PROPAGATION |
  • | |
  • | Collection: [ Item 1, Item 2, Item 3 (FAILS), Item 4, Item 5 ] |
  • | |
  • | - Item 1: Processed Successfully ---> vars.count = 1 |
  • | - Item 2: Processed Successfully ---> vars.count = 2 |
  • | - Item 3: Throws HTTP:CONNECTIVITY ERROR! |
  • | - Item 4: [SKIPPED / NEVER EXECUTED] |
  • | - Item 5: [SKIPPED / NEVER EXECUTED] |
  • | |
  • | Flow routes to <error-handler>: vars.count remains 2, error = HTTP:CONNECTIVITY |
  • +-----------------------------------------------------------------------------------------+
  • Resilient Pattern: Per-Item Error Isolation via <try> Scope

To allow iteration to continue even if individual records fail, wrap the inner processors in a Try scope with an On-Error Continue handler: <foreach collection="#[payload]" doc:name="For Each Resilient">

  • <try doc:name="Try Record Processing">
  • <http:request method="POST" config-ref="CRM_HTTP_Config" path="/sync">
  • <http:body><![CDATA[#[payload]]]></http:body>
  • </http:request>
  • <set-variable variableName="successCount" value="#[vars.successCount + 1]" doc:name="Increment Success" />
  • <error-handler>
  • <!-- On-Error Continue catches failure, logs it, and allows For Each to proceed to next item -->
  • <on-error-continue enableNotifications="true" logException="true" doc:name="Catch and Continue">

<logger level="ERROR" message="#['Failed to sync record: ' ++ payload.id ++ ' Reason: ' ++ error.description]" />

<set-variable variableName="failureList" value="#[vars.failureList + payload.id]" doc:name="Add to Failure List" />

  • </on-error-continue>
  • </error-handler>
  • </try>
  • </foreach>
  • 5. Streaming Data & Non-Repeatable Streams in For Each

When iterating over large datasets streamed from a Database ( <db:select> ) or File read operation, Mule 4 uses streaming cursor providers ( CursorProvider ).

Repeatable Streams (Default): Mule 4 caches consumed parts of the stream in memory (or temporary disk buffers if exceeding buffer thresholds). When <foreach> exits, the original stream can be re-read because the runtime manages cursor positions.

Non-Repeatable Streams: If non-repeatable streaming is configured, consuming the stream inside <foreach> drains the stream iterator. While <foreach> still restores the root payload reference, attempting to read that non-repeatable stream after <foreach> will result in a STREAM_MAXIMUM_SIZE_EXCEEDED or empty stream error.

6. Architectural Comparison: For Each vs. Parallel For Each vs. Batch Job

MuleSoft provides three distinct collection processing constructs. Knowing when to use each is a high-frequency exam topic:

Feature For Each ( <foreach> ) Parallel For Each ( <parallel-foreach> ) Batch Job ( <batch:job> )

Execution Threading Single calling thread (Sequential) Multiple worker threads (Concurrent / Parallel) Dedicated thread pool across multiple steps (Asynchronous)

Payload After Scope Restored to original inbound payload Aggregated array of iteration output messages BatchJobResult summary object (in On Complete)

Variable Scope Modifications persist across iterations and outside scope Modifications are isolated to each thread and lost upon exit Modifications become Record Variables ; lost outside batch job

Error Handling Aborts immediately on first unhandled error Processes all routes, then throws MULE:COMPOSITE_ROUTING Configurable tolerance ( maxFailedRecords , acceptPolicy )

Handoff Mode Synchronous (blocks calling flow) Synchronous (blocks until all parallel routes join) Asynchronous (immediate handoff to batch instance)

Queue Persistence None (in-memory only) None (in-memory only) Persistent Disk Queues (resilient across restarts)

Ideal Use Case Small/medium collections requiring ordered execution or variable accumulation Medium collections where independent I/O calls can run in parallel Massive volume (millions of records), ETL, bulk loading, multi-step staging

7. Exam Watch: Core For Each Scenarios

Important

Payload vs. Variable Rule Always remember: Payload is RESTORED; Variables PERSIST. If a flow transforms payload inside <foreach> , that transformed payload is lost after the scope closes. If you must retain results from each iteration, append them to a flow variable (e.g., vars.resultsCollection ).

Warning

Parallel For Each Variable Trap In <parallel-foreach> , variables set inside the scope do NOT propagate back to the parent flow . Only <foreach> propagates variable mutations back to the parent flow.

Tip

Counter Indexing The built-in counter ( vars.counter ) is 1-indexed (first item is 1 , second is 2 ), matching standard DataWeave and Mule conventions rather than 0-indexed Java arrays.