PracticeVideosBlogFlashcards

6.4 Flow Execution Architecture, Bulkification & Fault Paths

Key Takeaways

  • Flows are subject to standard platform governor limits, including 100 SOQL queries and 150 DML statements per synchronous transaction.

  • The golden rule of Flow design is to never place Data elements (Create, Update, Delete, Get Records) inside a Loop element.

  • Enterprise bulkification requires iterating over collections, modifying records via Assignment elements, adding to a new collection, and executing a single DML operation outside the loop.

  • Fault paths intercept runtime exceptions on Data and Action elements, enabling custom error logging, user-friendly notifications, or Custom Error element displays.

  • Flow debugging features include Run as Another User, Rollback Mode to prevent test data pollution, and declarative Flow Tests for regression protection.

Last updated: October 2026

Flow Execution Architecture, Bulkification & Fault Paths

Salesforce Flow operates on the exact same underlying multitenant database engine and execution runtime as Apex code. Consequently, flows are governed by the exact same Governor Limits that constrain programmatic development. When an automation violates a governor limit, the platform immediately aborts the transaction and rolls back all database modifications executed during that request.

For a Salesforce Platform App Builder, architecting flows that are fully bulkified, resilient against unexpected data exceptions, and thoroughly tested is essential for enterprise-grade deployments.


Multitenant Governor Limits & Platform Bulkification

Every automated transaction in Salesforce operates under strict runtime boundaries:

  • Total SOQL Queries Issued: 100 in the documented Flow transaction budget.
  • Total DML Statements Issued: 150 per transaction.
  • Total Records Retrieved by Queries: 50,000 records.
  • Total Records Processed by DML: 10,000 records.
  • Maximum CPU Time on Servers: 10,000 ms (10 seconds) in the documented Flow transaction budget.

Platform Automatic Bulkification

When a bulk operation occurs—such as a user importing 200 records via Data Loader, a third-party REST integration pushing a batch of contacts, or an Apex trigger updating multiple records—Salesforce groups records into batches of up to 200 records.

For Record-Triggered Flows, Salesforce creates a separate flow interview for each record in the batch. However, the platform automatically bulkifies data operations across interviews: if 200 flow interviews reach an identical Get Records element, Salesforce combines them into a single optimized SOQL query. Similarly, when interviews reach an identical Create Records element, Salesforce executes a single bulk DML insert statement.

Caution

The Bulkification Illusion: While Salesforce automatically bulkifies data elements across multiple concurrent interviews, platform bulkification does NOT protect against poor design inside a single flow! If a single flow interview contains an unbulkified loop, the transaction will crash with governor limit exceptions.


The Golden Rule of Flow Design: No DML or SOQL Inside Loops

Inside an individual flow interview, the most catastrophic architectural anti-pattern is placing a Data element (Get Records, Create Records, Update Records, Delete Records) inside a Loop element.

  ANTI-PATTERN: DML / SOQL INSIDE A LOOP (GOVERNOR LIMIT FAILURE)
  ┌──────────────────────────────────────────────────────────────┐
  │ Loop (Iterates 151 Times)                                    │
  │   └──► Update Records (DML Statement per iteration!)        │
  │          └──► CRASH: System.LimitException: Too many DML: 151 │
  └──────────────────────────────────────────────────────────────┘

  ENTERPRISE PATTERN: COLLECTION ASSIGNMENT (1 DML STATEMENT)
  ┌──────────────────────────────────────────────────────────────┐
  │ Loop (Iterates 151 Times)                                    │
  │   ├──► Assignment 1: Update field values on current item     │
  │   └──► Assignment 2: Add item to Target Collection Variable │
  │ Loop Exits (After Last Item)                                 │
  │   └──► Update Records (Single DML Statement on Collection!)   │
  └──────────────────────────────────────────────────────────────┘

Why Loops Multiply Limits

When a loop processes a collection of records, every element inside the loop executes once per item:

  • If a loop iterates over 101 records and contains a Get Records element, the flow executes 101 distinct SOQL queries, triggering a fatal System.LimitException: Too many SOQL queries: 101 error.
  • If a loop iterates over 151 records and contains an Update Records or Create Records element, the flow executes 151 separate DML statements, crashing the transaction with System.LimitException: Too many DML statements: 151.

The Enterprise Collection Loop Pattern

To safely process record collections without violating governor limits, app builders must master the Enterprise Collection Loop Pattern. This pattern relies on in-memory Assignment elements to stage changes and issues a single bulk DML statement outside the loop:

Step-by-Step Architecture

  1. Query Outside Loop (Get Records): Query the required records once before entering the loop. This consumes exactly 1 SOQL query and stores the results in a Record Collection Variable (colSourceRecords).
  2. Initialize Target Collection Variable: Create an empty Record Collection Variable in the Manager tab (e.g., colRecordsToUpdate).
  3. Loop Over Collection (Loop): Configure the Loop element to iterate through colSourceRecords. For each iteration, Flow Builder automatically creates a loop item variable representing the current record (currentItem_LoopName).
  4. Modify Record Attributes (Assignment Element 1): Use an Assignment element to modify field values on the loop item variable. For example: {!currentItem_LoopName.Status} Equals 'Closed'.
  5. Stage to Target Collection (Assignment Element 2): Use a second Assignment element (or add an assignment line) to append the modified loop item variable to your target collection variable using the Add operator: {!colRecordsToUpdate} Add {!currentItem_LoopName}.
  6. Execute Bulk DML Outside Loop (Update Records): Connect the loop's "After Last Item" path to a single Update Records element. Configure the element to update the entire colRecordsToUpdate collection.

By following this architecture, the flow issues one Get and one collection Update instead of one per item. Those operations can invoke other automation, which shares the transaction budget; row-count and CPU limits still apply.


Fault Paths & Exception Handling

Even a well-architected flow can encounter unexpected runtime exceptions: a record may fail a validation rule, a required field might be null, an external ID might be duplicated, or record lock contention may occur.

By default, when an unhandled exception occurs in a flow:

  • The entire transaction fails and rolls back all database changes.
  • The interacting user sees a generic, unhelpful error message: "An unhandled fault has occurred in this flow."
  • An automated technical fault email containing the stack trace is sent to the author or configured Apex exception email recipients.

Implementing Fault Connectors

In Flow Builder, every Data element (Get, Create, Update, Delete) and Action element supports a Fault Connector (represented by a red dashed line). When an exception occurs at that element, execution immediately diverts to the fault path rather than crashing the transaction.

Fault Handling Design Patterns

  • In Screen Flows: Route the fault connector to a custom Screen Element. Display a polite, user-friendly explanation along with the global error variable {!$Flow.FaultMessage} so the user understands why the operation failed and what corrective action to take.
  • In Record-Triggered & Autolaunched Flows: Route the fault connector to a Create Records element that inserts a detailed diagnostic record into a custom Error_Log__c object, capturing {!$Flow.FaultMessage}, {!$Flow.CurrentDateTime}, and the triggering record ID.
  • The Custom Error Element: Introduced to provide declarative inline error handling. In Record-Triggered Flows, app builders can route fault paths or validation checks to a Custom Error element. This displays a targeted message and intentionally rolls back the triggering change. A log record inserted in that same transaction also rolls back; use a separately designed diagnostic channel if logs must survive.

Flow Testing, Debugging & Governance

Before deploying flows to production, app builders must rigorously verify their logic using Flow Builder's native testing and debugging tools:

1. The Debug Tool

Accessible from the top button bar, the Debug Tool executes the flow directly within Flow Builder and provides a detailed step-by-step execution log on the right side of the canvas. The debug panel displays exact variable values, decision path evaluations, SOQL query results, and governor limit consumption.

2. Run Flow as Another User

Administrators can check Run flow as another user within the Debug panel. This allows testing the flow under the specific security context, Profile, Permission Sets, and Sharing Rules of a target end user (e.g., a standard sales rep or external community user) without needing to log in as that user.

3. Rollback Mode

When testing flows that execute DML operations (Create, Update, Delete Records), checking Rollback Mode in the Debug tool executes all flow logic and logs all outcomes, but automatically rolls back all database modifications at the end of the debug run. This prevents dummy test records from cluttering the sandbox environment.

4. Declarative Flow Tests

Record-Triggered Flows feature a native View Tests panel that allows app builders to build and automate declarative test suites. Similar to Apex unit tests, Flow Tests define mock triggering records, set trigger conditions (create or update), and define Assertion criteria (e.g., verifying that after the flow executes, Opportunity.StageName equals Closed Won). These tests can be run on demand to protect against regression during deployments.


Bulkification Anti-Pattern vs. Enterprise Pattern

Architectural FeatureUnbulkified Anti-Pattern (Failure)Enterprise Bulkified Pattern (Best Practice)Governor Limit Impact
SOQL Query PlacementGet Records placed inside LoopGet Records executed once outside Loop1 query vs. N queries (Exceeds 100 SOQL limit at 101 items)
DML Statement PlacementCreate / Update placed inside LoopCreate / Update executed once outside Loop on Collection1 DML vs. N DML (Exceeds 150 DML limit at 151 items)
In-Memory Collection BuildingUpdating records individuallyStaging updates in a collection variable via Add operatorZero DML overhead during loop iterations
Transaction CPU TimeHigh server roundtrips per itemSingle bulk database operationEliminates excessive database context switches
Exception HandlingNo fault paths; unhandled system crashFault path routes to Custom Error or Error_Log__cClean user recovery and complete auditability

Best Practices & Common Exam Traps

Important

The Collection Add Operator: When appending a modified record to a Record Collection Variable inside a loop assignment, always use the Add operator ({!colTarget} Add {!currentItem}). Using the Equals operator will overwrite the entire collection with that single record, resulting in only the last processed item being saved!

Tip

Safe Rollback Mode for User Testing: Always activate Rollback Mode when debugging complex Record-Triggered Flows in sandboxes with active integrations. Database rollback cannot undo external callouts or work committed in earlier transactions. Use isolated test endpoints and mock actions where supported.

Common Exam Traps

  • Trap 1: Believing platform bulkification allows DML inside loops. Platform bulkification merges operations across separate record interviews in a batch; it does not bulkify elements repeated within a single interview's loop. DML inside a loop remains a fatal violation.
  • Trap 2: Forgetting to clear single record variables in loops. When manually building new child records inside a loop using a single record variable, ensure you reset or clear the variable's fields before assigning new values, or create new items properly, to avoid duplicating stale data across records.
  • Trap 3: Neglecting Fault Paths on external Actions. External HTTP callouts and invocable Apex actions are prone to network timeouts and service downtime. Leaving Action elements without fault paths causes unhandled transaction failures whenever external endpoints experience latency.

What Fault Handling Does Not Catch

Governor-limit exceptions are not recoverable through a fault connector: exceeding the transaction budget rolls back the transaction even if a connector is defined. For recoverable element errors, a handled fault can continue execution and commit earlier pending changes. Do not assume that displaying a Screen or creating a log undoes prior successful operations. Before deploying, test an intentional failure after an earlier write and verify the resulting database state.

Debug-as-another-user is available only in a sandbox after the org setting is enabled. System-context flows continue to bypass the user's CRUD/FLS even when a different running user is selected. Debug tests one flow path rather than the complete production save ecosystem; run representative sandbox transactions and bulk loads as well.

Official Source Check

Checked October 19, 2026: Flow transaction limits and rollback.

Loading diagram...
Enterprise Bulkification: The Collection Loop Architecture Pattern
Test Your Knowledge

Universal Containers has an automated requirement where updating an Account status to 'Suspended' must automatically close all related open Opportunities as 'Closed Lost'. In sandbox testing with a bulk data load of 250 Accounts, the Record-Triggered Flow crashes with a System.LimitException: Too many SOQL queries: 101 error. Inspection reveals a Get Records element positioned inside a loop iterating over Accounts. How should the app builder refactor this flow to follow enterprise bulkification architecture?

A

Increase the transaction governor limit by converting the flow to call an asynchronous Apex invocable method

B

Split the flow into two separate flows using Flow Trigger Order values of 10 and 20

C

Move the Get Records element outside the loop to query all relevant Opportunities once, use in-memory assignments to stage updates, and issue a single Update Records DML outside the loop

D

Add a pause element inside the loop to reset the SOQL query counter after every 50 records

Test Your Knowledge

An immediate after-save flow cannot update required inventory records because a validation rule rejects the change. The order must not save in a partially completed state. Which design gives the user a clear message and rolls back the order?

A

Deactivate every inventory validation rule.

B

Replace the automation with a legacy workflow update.

C

Create an Error_Log__c record and assume it survives any rollback.

D

Route the Update Records fault to Custom Error; capture durable diagnostics through a separately designed channel.

Test Your Knowledge

An app builder has created a complex Screen Flow that calculates insurance premiums and creates policyholder records. Before deploying to production, the app builder needs to test the execution path, variable assignments, and decision outcomes under the persona of a Call Center Representative without committing dummy test records to the sandbox database. Which Flow Builder debugging features should the app builder utilize?

A

Activate the flow and execute it directly in the live Lightning Record Page as a System Administrator

B

Use the Flow Builder Debug tool, check 'Run flow as another user', and select 'Rollback mode'

C

Deploy the flow as an unmanaged package and run standard Apex unit tests with SeeAllData=true

D

Export the flow metadata and inspect variable assignments using the Developer Console log inspector

Sections you finish are checked off in the contents.