Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
Diagram illustrating efficient Salesforce Flow bulk processing techniques for handling numerous records.
Flow

How to handle bulk record processing in Flows

The short answer

This guide explains how to design Salesforce Flows for bulk record processing to remain governor-limit safe during multi-record transactions. It outlines bulk-safe Flow design patterns, execution contexts, error handling strategies, and guidelines for offloading high-volume operations to Apex.

Key takeaways Use before-save record-triggered flows for same-record updates to eliminate unnecessary DML operations and improve performance. Avoid queries and DML operations inside loops by accumulating modified records into a collection variable and executing a single update after the loop. Use scheduled paths to defer non-immediate processing and lower governor limit pressure during bulk operations. Implement fault paths and custom object logging to capture errors and prevent an unhandled exception from rolling back the entire transaction. Delegate processing to asynchronous Apex using invocable methods when data volumes, joins, or execution complexity exceed Flow limits.

Introduction

Salesforce Flow is bulk-aware when you design it that way, and quietly not when you do not. Record-triggered and auto-launched Flows run across batches of up to 200 records per transaction, so a pattern that behaves on one record can blow a governor limit the first time somebody runs a data load. This post covers the patterns that hold up under volume and the point where you should stop and write Apex.

Key concepts

Four things to design around:

  • Flows run in bulk: record-triggered Flows execute for batches of records, up to 200 per transaction.
  • Keep DML and queries out of loops. Accumulate the records and run one bulk operation afterwards.
  • Use before-save flows, the fast field updates, wherever the requirement allows.
  • When volume or complexity outgrows Flow, move the work to asynchronous Apex (Queueable or Batch) behind an invocable method.

Before save vs after save vs scheduled

Before-save record-triggered flows are the fastest way to set fields on the record that triggered them. There is no extra DML, which makes them the right default for simple derived-field updates across a lot of records.

After-save flows are what you need when the logic creates or updates related records, makes callouts, or depends on record IDs. They are still bulk-capable, but keeping the operations bulk-friendly is now your job.

Scheduled paths take deferred work you do not need results from in the same transaction. They run in bulk too, and they take pressure off the immediate transaction.

Flow elements & patterns for bulk processing

  • Get Records fetches related data in one operation instead of firing on every pass through a loop.
  • Loop plus Assignment: iterate only to build an output collection, and keep the update out of the loop.
  • Update Records takes a collection variable and does all the DML in a single action.
  • Collection filters, Decision elements and filtered Get Records cut the set down before you process it.
  • Subflows and invocable actions hold repeated logic, or hand the heavier and asynchronous work to Apex.

Typical bulk pattern (step-by-step)

  1. The record-triggered Flow starts with a collection of triggering records.
  2. A single Get Records fetches the related records for all of them, never inside a loop.
  3. The loop walks the triggering records and Assignment builds a collection of the ones that changed.
  4. After the loop, one Update Records writes the whole collection in bulk.

Example pseudo-assignments (Flow logic expressed conceptually):

// inside loop for each triggeringRecord if (needsUpdate) { updatedRecord = triggeringRecord; // modify fields as needed UpdatedCollection = UpdatedCollection + {updatedRecord}; } // after loop Update Records using UpdatedCollection

Avoid common anti-patterns

  • A Get Records and an Update Records inside a Loop. That multiplies your SOQL and DML by the number of records.
  • Heavy formulas or long Decision chains inside a loop, which force more operations than the work needs.
  • Screen Flows for bulk processing. Screens are interactive and single-record by nature.

Error handling & partial failures

Flows run inside a transaction, so an unhandled error can roll the whole thing back. To contain a failure and let a large job finish what it can:

  • Split the processing into scheduled or asynchronous chunks.
  • Use Try/Catch patterns with Fault paths, capture the failed record IDs, and log the details to a custom object for retry.
  • For real retry semantics, hand the work to an invocable Queueable that can process subsets and handle partial commits.

When to use Apex instead

Flow covers a lot, but very large volumes, complex joins and long-running operations belong in Apex, Queueable or Batchable. An @InvocableMethod wrapper lets Flow pass collections into that Apex, so you get batch processing and tighter control over limits without giving up the declarative front end.

public with sharing class FlowInvocableExample { @InvocableMethod public static void process(List recordIds) { // call Queueable or Batch Apex to process large volumes } }

Testing & monitoring

  • Load-test with Data Loader to push 200-record batches, or larger through scheduled Flows.
  • Read debug logs and paused Flow interviews to see how large the collections get and how many elements ran.
  • Watch the numbers on Setup > Process Automation Usage and Limits.

Practical checklist

  • Before-save for same-record fast field updates.
  • One Get Records for related data, never a query inside the loop.
  • Collect the changes, then run one Update Records.
  • Subflows and invocable Apex for anything reusable or heavy.
  • Fault paths and logging on every path that can fail.
  • Load-test with realistic batch sizes and watch the limits.

Prototype with realistic volumes before you ship. A Flow that passes a two-record test tells you nothing about what it does at 200, and a production data load is a bad place to find out.

Frequently asked questions

How do you bulkify a loop in Salesforce Flow?

Retrieve related records prior to the loop with a single Get Records element rather than querying inside iterations. Within the loop, use an Assignment element to add modified records to a collection variable, then execute a single Update Records element after the loop completes.

When should you use before-save versus after-save flows?

Use before-save flows for fast field updates on the triggering record to avoid extra DML statements. Use after-save flows when your logic requires record IDs, updates related records, or performs external actions such as callouts.

When should you use Apex instead of Flow?

Use Apex when processing requirements involve very large data volumes, complex table joins, or long-running operations that exceed Flow limits. You can expose Queueable or Batch Apex to Flow using an @InvocableMethod wrapper.

How do you handle partial failures in bulk Flows?

Configure fault paths to capture failed record IDs and log error details to a custom object for retry. For advanced partial commit and retry requirements, offload processing to an invocable Queueable Apex class.

Newsletter

One email every Tuesday

New guides, tool updates, and the release-note changes that break things.

No spam. Unsubscribe in one click.

Comments

Loading comments...

Leave a Comment