Flow Overview
Salesforce Flow is a powerful automation tool that helps you create complex business processes with a visual interface, eliminating the need for code in many scenarios.
Key Features
- Visual development: Drag-and-drop interface for building automation
- No-code solution: Create complex logic without writing Apex
- Multiple types: Screen flows, record-triggered flows, scheduled flows, and more — see Flow Types
- Data manipulation: Create, read, update, and delete records
- User interaction: Collect information through screens
- Integration: Call Apex, make HTTP callouts to external systems, react to platform events
Flow Is THE Automation Tool Now
Salesforce retired its older rule-based automation tools — every declarative automation investment goes into Flow. If you inherit legacy automations, the Migrate to Flow tool (Setup → Migrate to Flow) converts them into record-triggered flows. The practical rule of thumb: Flow first, Apex when Flow strains — the decision table in Plan & Design shows exactly where that line sits, and the Apex guide covers the other side of it.
How to Learn This Guide (in order)
| Stage | Sections, in sequence | You can now… |
|---|---|---|
| Start Here | This page → Builder Tour → Flow Types → Plan & Design | Navigate Builder and name every flow type |
| L1 · Building Blocks | Variables → Collections → Resources → Logic → Data | Read and build any flow's internals |
| L2 · Flow Types | Record-Triggered → Scheduled → Autolaunched → Orchestration | Pick and configure the right trigger for any automation |
| L3 · Screen Flows | Elements → Deep Dive | Ship guided UIs users actually like |
| L4 · Reliability | Errors & Monitoring → Performance → Testing → Best Practices | Build automation that survives production |
| L5 · Extensibility | Invocable Apex → Callouts, Events & Agents | Connect Flow to code, APIs and AI |
| L6 · Architect | Security Context → Deploy → Capstone | Own end-to-end process architecture |
Flow Types: The Complete Map
Picking the right flow type is the first design decision of every automation. Here's the current, complete taxonomy — the five core types you'll use weekly, then the specialized ones you should recognize.
The Core Five
| Type | Runs when… | Use it for |
|---|---|---|
| Screen Flow | A user launches it (button, action, Lightning page, Experience site) | Guided wizards: data entry, call scripts, self-service processes |
| Record-Triggered Flow | A record is created, updated, or deleted | Replaces the retired legacy automation tools and most Apex-trigger use cases — see its own section |
| Schedule-Triggered Flow | A schedule fires (once / daily / weekly) for a batch of records | Nightly cleanups, reminder generation, periodic recalculation |
| Platform Event–Triggered Flow | A platform event message is received | Event-driven integrations; reacting to external systems |
| Autolaunched Flow | Called by something else: Apex, REST API, another flow (subflow), or an Agentforce action | Reusable background logic with no UI |
Specialized Types Worth Recognizing
- Subflow: not a separate build type, but the reuse pattern — autolaunched (or screen) flows invoked from parent flows so shared logic lives once.
- Approval Flows / Approval Orchestration: the modern, Flow-Builder-based generation of approval processes — multi-stage, multi-approver, far beyond classic Approval Processes.
- Flow Orchestration: coordinates multiple flows and human steps into staged, long-running processes (e.g., onboarding). Now a standard feature — the usage-based pricing caps were removed.
- Evaluation Flow: the autolaunched variant orchestrations use to decide whether a stage is complete.
- Template-Triggered Prompt Flow: grounds AI prompt templates with record data — the Flow↔Prompt Builder bridge.
- Automation Event-Triggered Flow: a newer addition — trigger on events like files being attached to records that match criteria.
- Contact Request / Field Service Mobile / Cadence Step flows: product-specific screen-flow variants (Experience Cloud, Field Service, Sales Engagement).
Sources: Salesforce Help — Flows · Flow Types (Help)
Flow Builder
The Flow Builder is the visual interface where you design and configure your flows.
Key Components
-
Canvas:
- Drag-and-drop workspace for building your flow
- Elements are connected to define the flow's logic
-
Toolbox:
- Contains all available elements (logic, data, screens, etc.)
- Elements are organized into categories
-
Manager:
- Manage variables, constants, and other resources
- View and edit element properties
-
Debugger:
- Test your flow with sample data
- Step through execution to identify issues — see Testing & Debugging
What the Builder Can Do Now (2025–26)
- Auto-Layout canvas is the default — elements snap into a clean vertical flow; recent releases added smoother zoom, auto-alignment, and collapsible branches (fault paths can be collapsed too).
- Version comparison: diff two versions of the same flow side by side to see exactly what changed — invaluable before activating someone else's edit.
- Quick Resources: the resource picker now surfaces frequently used and contextually valid resources first, filtered by expected data type.
- Formula builder with real-time syntax checking, and searchable element/resource panels.
- Build with AI: describe automation in natural language and let Einstein generative AI draft the flow — then review every element it created (treat it like a junior admin's first draft).
Screen Elements
Screen elements allow you to create interactive interfaces for your flows.
Common Screen Components
-
Display Text:
- Show information to users
- Can include merge fields from variables
-
Input Fields:
- Collect text, numbers, dates, etc.
- Can be required or have validation
-
Radio Buttons/Checkboxes:
- Present multiple options
- Single or multi-select
-
Buttons:
- Navigation between screens
- Can have conditional visibility
Screen Flow Example
// Example of how a screen flow might be structured in metadata
<flow>
<screen>
<name>ContactInformation</name>
<label>Contact Information</label>
<fields>
<field>
<name>FirstName</name>
<dataType>String</dataType>
<isRequired>true</isRequired>
</field>
<field>
<name>LastName</name>
<dataType>String</dataType>
<isRequired>true</isRequired>
</field>
</fields>
</screen>
</flow>
Logic Elements
Logic elements control the flow's decision-making and processing.
Decision: Outcomes, Order, Default Path
- A Decision holds ordered outcomes, each with conditions (all/any/custom logic like
1 AND (2 OR 3)); the record takes the first outcome that matches — order the specific before the general. - The default outcome is your safety net: give it a real name ("No match — log and end") and real handling — an unlabeled dead-end default is where records silently vanish.
- Useful operators beyond Equals:
Is Changed(record-triggered),Is Blank/Is Empty,Contains,Starts With— and date operators likeIs Today.
Assignment: The Operators, Explained
| Operator | Does | Watch for |
|---|---|---|
| Equals | Overwrites the variable | The default; nothing tricky |
| Add | Number: adds · Text: concatenates · Collection: appends an item | The triple meaning surprises people — check the variable type |
| Subtract | Numeric subtraction; date minus days | Numbers/dates only |
| Add at Start / Remove … | Collection surgery: prepend, remove first/all/position, deduplicate | Collection variables only |
| Equals Count | Stores a collection's size into a number variable | Cheaper than looping to count |
Loops: Iterate Correctly
- A Loop hands you one item at a time in the loop variable; direction can be first-to-last or reversed.
- The golden pattern: inside the loop, modify the loop variable and Add it to a results collection (Assignment) — after the loop, one Update Records on the collection. DML inside a loop is the #1 flow failure (Best Practices).
- Reshaping collections (map fields from one object to another)? The Transform element replaces the whole loop+assignment dance.
Wait & Pause
- Wait elements pause until a time or platform event — fine for short operational pauses; if you're orchestrating multi-day human processes with Waits, you want Flow Orchestration instead.
Data Elements
Data elements interact with Salesforce records and external systems.
Key Data Elements
-
Get Records:
- Retrieve records from Salesforce
- Filter with conditions or IDs
-
Create/Update/Delete Records:
- Modify data in Salesforce
- Can process single records or collections
-
Action:
- Call external systems or Apex
- Invoke predefined actions
-
Subflow:
- Call another flow
- Pass parameters and receive outputs
Get Records Example
// Example of a Get Records element configuration
{
"name": "GetAccount",
"label": "Get Account",
"object": "Account",
"filterLogic": "AND",
"filters": [
{
"field": "Id",
"operator": "equals",
"value": "{!recordId}"
}
],
"outputAssignments": [
{
"field": "AccountNumber",
"variable": "accountNumber"
}
]
}
Variable Types
Variables store data that can be used throughout your flow.
Supported Variable Types
-
Text:
- String values
- Can have character limits
-
Number:
- Numeric values
- Can specify decimal places
-
Boolean:
- True/false values
-
Date/DateTime:
- Date and time values
-
Picklist:
- Predefined set of values
Collection Variables
Collection variables store multiple values and are essential for processing sets of records.
Working with Collections
-
Creating Collections:
- Initialize empty collections
- Populate from Get Records elements
-
Modifying Collections:
- Add items with Assignment elements
- Remove items with Assignment elements
-
Processing Collections:
- Use Loop elements to iterate
- Access collection size with formula
Collection Example
// Example of working with collections in a flow
{
"variables": [
{
"name": "contactList",
"dataType": "SObject",
"isCollection": true,
"objectType": "Contact"
},
{
"name": "filteredContacts",
"dataType": "SObject",
"isCollection": true,
"objectType": "Contact"
}
],
"elements": [
{
"type": "getRecords",
"outputReference": "contactList",
"filter": "AccountId = '{!recordId}'"
},
{
"type": "loop",
"collectionReference": "contactList",
"elementVariable": "currentContact",
"logic": {
"type": "decision",
"conditions": [
{
"leftValue": "{!currentContact.DoNotCall}",
"operator": "equals",
"rightValue": "false"
}
],
"trueBranch": {
"type": "assignment",
"assignments": [
{
"variable": "filteredContacts",
"operation": "add",
"value": "{!currentContact}"
}
]
}
}
}
]
}
Resource Management
Efficiently manage all the resources (variables, formulas, etc.) in your flow.
Resource Types
-
Variables:
- Store data values
- Can be input/output variables
-
Constants:
- Fixed values used in the flow
-
Formulas:
- Calculate values dynamically
- Can reference other resources
-
Text Templates:
- Reusable text with merge fields
Formula Example
// Example formula to calculate days between two dates
IF(
NOT(ISNULL({!startDate})) && NOT(ISNULL({!endDate})),
DATEVALUE({!endDate}) - DATEVALUE({!startDate}),
NULL
)
Error Handling
Proper error handling ensures your flows can gracefully handle unexpected situations.
Error Handling Techniques
-
Fault Paths (your try/catch):
- Every data element (Create/Update/Get/Delete) and action can have a fault connector — drag a second connection from the element and it becomes the "on failure" route
- Inside a fault path, the merge field
{!$Flow.FaultMessage}holds the error text;{!$Flow.InterviewGuid}uniquely identifies the run, and in record-triggered flows{!$Record}tells you which record was involved - You can collapse fault paths on the canvas so happy-path logic stays readable
-
Custom Error element (record-triggered flows):
- Block a save with a precise, user-friendly message — either at the top of the record page or attached to a specific field. This is the Flow equivalent of
addError()in Apex triggers, and richer than a validation rule (it can check related records first)
- Block a save with a precise, user-friendly message — either at the top of the record page or attached to a specific field. This is the Flow equivalent of
-
Screen Messages (screen flows):
- Route fault paths to an error screen that explains what happened and what to do — never let a flow die with the default unhandled-fault page
The Production Pattern: Fault Path → Log → Notify
Build this once as a subflow and reuse it from every fault connector:
- Step 1 — Create Records element (inside the fault path) inserts an
Error_Log__crecord: the flow name (passed in as a subflow input — there's no global variable for it),{!$Flow.FaultMessage},{!$Flow.InterviewGuid}, the record Id, and{!$Flow.CurrentDateTime}. - Step 2 — Decision: is this failure user-recoverable? If yes (screen flow), show a retry screen; if no, continue.
- Step 3 — Notify: send a custom notification or email alert to the admin group with the log record link.
- Why a subflow: one place to improve logging forever; every flow's fault connectors just call it with two inputs (fault message, record Id).
Monitoring Flows in Production
- Flow error emails: set Process Automation Settings to send failures to an apex-style ops address or the last modifying admin — and actually route them to a queue someone reads.
- Paused & failed interviews: Setup shows stuck runs; a weekly triage (resume, delete, fix root cause) keeps the backlog honest.
- Your own error log: the fault-path subflow pattern above gives you reportable
Error_Log__cdashboards — trend by flow name and fault message; a spike is a release regression announcing itself. - Debug logs capture flow element execution alongside Apex when you need forensic depth (Apex guide).
Transaction truth: a fault path doesn't roll back what already committed earlier in the same transaction the way an unhandled error would — handle errors deliberately, and put risky operations as close together as possible. For guaranteed all-or-nothing semantics across many operations, that's a sign the logic belongs in invocable Apex with a savepoint.
Apex Integration
Extend your flow's capabilities by integrating with Apex code when needed.
Integration Methods
-
Invocable Actions:
- Call Apex methods marked with @InvocableMethod
- Pass parameters and receive outputs
-
Flows from Apex:
- Launch an autolaunched flow programmatically with the
Flow.Interviewclass - Useful when admin-maintained logic (the flow) should run inside developer-controlled processing
- Launch an autolaunched flow programmatically with the
Invocable Apex Example (Bulkified)
One critical detail most tutorials miss: when your flow triggers on 200 records, Salesforce batches all their requests into a single call to your invocable method. Queries and DML must therefore sit outside the request loop — exactly like a trigger handler:
public with sharing class ContactProcessor {
@InvocableMethod(label='Mark Account Contacts Processed'
description='Flags every contact under the given accounts')
public static List<Result> processContacts(List<Request> requests) {
// 1. Gather ALL inputs first (the flow batches up to 200 requests)
Set<Id> accountIds = new Set<Id>();
for (Request req : requests) {
accountIds.add(req.accountId);
}
// 2. ONE query, ONE update — regardless of batch size
Map<Id, Integer> countsByAccount = new Map<Id, Integer>();
List<Contact> toUpdate = [SELECT Id, AccountId FROM Contact
WHERE AccountId IN :accountIds WITH USER_MODE];
for (Contact c : toUpdate) {
c.Processed__c = true;
c.ProcessedDate__c = Date.today();
Integer n = countsByAccount.get(c.AccountId);
countsByAccount.put(c.AccountId, n == null ? 1 : n + 1);
}
update as user toUpdate;
// 3. Return one Result per Request, in the same order
List<Result> results = new List<Result>();
for (Request req : requests) {
Result res = new Result();
Integer n = countsByAccount.get(req.accountId);
res.processedCount = n == null ? 0 : n;
results.add(res);
}
return results;
}
public class Request {
@InvocableVariable(label='Account ID' required=true)
public Id accountId;
}
public class Result {
@InvocableVariable(label='Processed Contact Count')
public Integer processedCount;
}
}
In Flow Builder this appears as an Action element named "Mark Account Contacts Processed." Let real exceptions surface (don't swallow them into a success flag) — the flow's fault path is designed to catch them.
Launching a Flow from Apex
Map<String, Object> inputs = new Map<String, Object>{
'inputAccountId' => acct.Id // must match the flow variable's API name
};
Flow.Interview interview = Flow.Interview.createInterview('Account_Cleanup_Flow', inputs);
interview.start();
// Read an output variable after the run
Decimal score = (Decimal) interview.getVariableValue('outputRiskScore');
Record-Triggered Flows
Record-triggered flows automate processes when records are created, updated, or deleted, providing a powerful no-code alternative to Apex triggers.
The Four Configuration Decisions
-
1. Trigger event:
- A record is created, updated, created or updated — or deleted (delete flows run just before the record leaves the database, so
{!$Record}is still readable)
- A record is created, updated, created or updated — or deleted (delete flows run just before the record leaves the database, so
-
2. Optimization — the before/after choice:
- Fast Field Updates (before save): modify the triggering record's own fields — no extra DML, roughly 10× faster. Use whenever the flow only touches
{!$Record} - Actions and Related Records (after save): record has an Id; create/update other records, send emails, call actions, run async paths
- Fast Field Updates (before save): modify the triggering record's own fields — no extra DML, roughly 10× faster. Use whenever the flow only touches
-
3. Entry conditions:
- Filter which records even start the flow — including the crucial "only when a record is updated to meet the condition" option (fires on the transition, not on every edit while the condition stays true)
Is Changed/Is Blankoperators and formula entry conditions handle the rest
-
4. Path timing:
- Run Immediately in the same transaction, or Run Asynchronously after commit — the async path is where callouts and slow work belong (it's Flow's Queueable)
- Scheduled paths run minutes/days after the trigger, relative to a date field
What the Real Metadata Looks Like
Flows are XML metadata (retrieve one with sf project retrieve start -m Flow:Your_Flow). The <start> element holds everything configured above — worth recognizing for code review and version control:
<!-- excerpt from force-app/main/default/flows/Account_Priority.flow-meta.xml -->
<start>
<object>Account</object>
<recordTriggerType>CreateAndUpdate</recordTriggerType>
<triggerType>RecordBeforeSave</triggerType>
<filterLogic>and</filterLogic>
<filters>
<field>Industry</field>
<operator>EqualTo</operator>
<value><stringValue>Technology</stringValue></value>
</filters>
<filters>
<field>AnnualRevenue</field>
<operator>GreaterThan</operator>
<value><numberValue>1000000.0</numberValue></value>
</filters>
</start>
Recursion Control
- The loop to prevent: your flow updates the record → the update re-fires the flow. The platform caps runaway recursion, but the real fix is design.
- Defense 1 — transition-style entry conditions: "only when a record is updated to meet the condition" fires once, on the change, not on every subsequent save.
- Defense 2 — before-save for same-record fields: before-save changes don't trigger another save cycle the way an after-save Update Records on the same record does.
- Defense 3 — guard conditions: a Decision checking
Is Changedon the exact fields you react to, so edits your own flow made don't qualify.
Transaction Boundaries
- Immediate paths run inside the record's transaction: an unhandled flow failure rolls back the whole save (including whatever the user or integration was doing). A handled fault path commits what already succeeded — decide deliberately which you want.
- Async and scheduled paths run in separate transactions after commit — failures there can't roll back the original save, which is exactly why callouts and risky work belong on them.
- All-or-nothing across many operations with rollback control is Apex territory (savepoints) — the boundary in Apex Integration.
Common Use Cases
-
Field Validation:
- Before Save: Validate complex business rules
- Add error messages to prevent save
-
Field Automation:
- Before Save: Calculate values or set defaults
- After Save: Update roll-up summaries
-
Related Records:
- After Save: Create child records
- After Save: Update related objects
-
Notifications:
- After Save: Send email alerts
- After Save: Post to Chatter
Best Practices
// Example of optimized record-triggered flow
{
"triggerType": "RecordAfterSave",
"object": "Opportunity",
"entryConditions": {
"formula": "AND(
ISCHANGED(StageName),
ISPICKVAL(StageName, 'Closed Won'),
$Record.Amount > 50000
)"
},
"optimization": {
"runAsynchronously": true,
"filterChangedFields": ["StageName"],
"preventRecursion": true
},
"actions": [
{
"type": "createRecords",
"object": "Task",
"values": {
"Subject": "Follow up on Closed Won",
"Priority": "High",
"WhatId": "$Record.Id"
}
}
]
}
-
Entry Conditions:
- Use precise criteria to limit execution
- Filter for changed fields when appropriate
-
Bulk Processing:
- Always design for multiple records
- Use collections instead of single-record operations
-
Error Handling:
- Implement fault paths for DML operations
- Log errors to custom objects when needed
-
Performance:
- Run asynchronously for complex operations
- Minimize SOQL queries and DML statements
Migration from Triggers
When converting from Apex triggers to record-triggered flows:
- Start with simple field updates and validations
- Use subflows to organize complex logic
- For advanced scenarios, combine with invocable Apex
- Test thoroughly with bulk data
- Monitor execution in Flow Debug Logs
// Example of trigger logic converted to flow
// Apex Trigger:
trigger AccountTrigger on Account (after update) {
if(Trigger.isAfter && Trigger.isUpdate) {
List tasks = new List();
for(Account acc : Trigger.new) {
if(acc.Industry == 'Technology' &&
acc.AnnualRevenue > 1000000) {
tasks.add(new Task(
Subject = 'High Value Tech Account',
WhatId = acc.Id
));
}
}
insert tasks;
}
}
// Equivalent Flow Configuration:
{
"triggerType": "RecordAfterSave",
"object": "Account",
"conditions": [
{
"field": "Industry",
"operator": "equals",
"value": "Technology"
},
{
"field": "AnnualRevenue",
"operator": "greaterThan",
"value": "1000000"
}
],
"actions": [
{
"type": "createRecords",
"object": "Task",
"values": {
"Subject": "High Value Tech Account",
"WhatId": "$Record.Id"
}
}
]
}
Scheduled Flows
Scheduled flows allow you to automate processes that need to run at specific times or intervals, similar to scheduled Apex jobs but without writing code.
Key Features
-
Time-Based Execution:
- Run daily, weekly, or monthly
- Specific time or recurring schedule
-
Batch Processing:
- Process large data volumes in batches
- Ideal for data maintenance tasks
-
Flexible Scheduling:
- Schedule via UI or metadata API
- Pause and resume schedules
How Scheduled Runs Actually Work
- Configure the schedule (start date/time + once/daily/weekly) directly on the flow's Start element, and optionally choose an object + filter — the flow then runs once per matching record, with
{!$Record}populated. - Records are processed in batches (default 200 per batch); a batch-size control was recently added on the Start element so you can shrink batches when each record's processing is heavy (e.g., callouts via subflow).
- Without an object selected, the flow runs once per schedule — the pattern for "do one thing nightly" jobs that fetch their own data with Get Records.
- The org-wide limit to remember: schedule-triggered flows can process a large but bounded number of records per 24 hours (250,000 or your license-based limit, whichever is greater) — past that, batches fail. High-volume archival belongs in Batch Apex or Apex Cursors.
Real Example: Deactivate Stale Portal Users Weekly
- Schedule: weekly, Sunday 02:00.
- Object + filter: User, where
IsActive = trueANDLastLoginDate < LAST 90 DAYS(formula entry condition). - Logic per record: Decision (exclude admin profiles) → Update
{!$Record}IsActive = false → add Id to a collection. - Wrap-up: fault path logs failures to
Error_Log__c; a final email alert summarizes the run to the admin team.
Best Practices
- Test with small batch sizes and a sandbox subset before production
- Make per-record logic idempotent — a rerun on the same record must be harmless
- Include fault paths; scheduled failures are silent until you log and alert on them
- The schedule runs in the org's default timezone — double-check when your admins are global
Autolaunched Flows
Autolaunched flows run without user interaction, triggered by processes, platform events, or other automation tools.
Triggering Methods
-
Other Flows (Subflow):
- The most common caller — build shared logic once (error logging, record scoring) and invoke it everywhere with input/output variables
-
Apex Code:
- Call flows programmatically with the
Flow.Interviewclass — example in Apex Integration
- Call flows programmatically with the
-
REST API:
POST /services/data/vXX.X/actions/custom/flow/Your_Flow_API_Name— external systems can invoke a flow directly with JSON inputs
-
Agentforce Actions:
- Autolaunched flows are one of the primary action types AI agents call — the flow's clear input/output descriptions become instructions the agent's reasoning engine reads (see the Agentforce guide)
- Custom buttons / links and Einstein Bots round out the launch options.
Note: flows that react to platform events are their own flow type (Platform Event–Triggered Flow) — you pick the event when creating it, and {!$Record} holds the event message.
Real Example: Reusable "Log Error" Subflow
- Type: autolaunched; inputs:
inFlowName(Text),inFaultMessage(Text),inRecordId(Text). - Logic: Create
Error_Log__c→ Decision: message contains "UNABLE_TO_LOCK_ROW"? → if yes, send admin a custom notification (locking issues need human eyes). - Used by: every fault connector in every other flow — one subflow call with three inputs. This is the pattern from Error Handling made concrete.
Use Cases
- Shared subflow logic invoked from many parent flows
- Flow logic exposed to external systems via REST
- Agent actions for Agentforce
- Background calculations invoked from Apex at precise points in a transaction
Advanced Best Practices
Mastering these advanced techniques will help you build enterprise-grade flows that are performant, maintainable, and scalable.
Performance Optimization
-
Query Optimization:
- Filter records at the SOQL level
- Only retrieve needed fields
-
Bulkification:
- Process records in collections
- Avoid DML in loops
-
Caching:
- Store frequently used data in variables
- Use platform cache for cross-flow data
Maintainability
-
Documentation:
- Add descriptions to all elements
- Include flow overview documentation
-
Naming Conventions:
- Consistent naming for variables and elements
- Use prefixes for resource types
-
Version Control:
- Manage flows in source control
- Implement change management processes
Governor Limit Management
Flows run inside the same transaction limits as Apex — 100 SOQL queries, 150 DML statements, CPU time (see the Apex guide's Governor Limits section). Each Get Records is a query; each Create/Update/Delete Records element is a DML statement. The classic mistake and its fix:
- DML inside a Loop: Loop over 500 contacts → Update Records inside the loop = 500 DML statements = crash at 150.
- Assign inside, commit after: inside the loop, modify the record variable and Add it to a collection variable with an Assignment element; place ONE Update Records element after the loop pointing at the collection. 500 records, 1 DML.
- Filter in Get Records, not in the loop: conditions belong in the Get Records element (query-level filtering), and check "store only the fields you need."
- One record-triggered flow per object per event type where practical — use entry conditions and Decision elements for branching, and the Trigger Order field (1–2000) when multiple flows must coexist predictably.
- Know when to leave Flow: tens of thousands of records, complex rollbacks, or heavy math → invocable Apex or Batch Apex. Flow and Apex share the lifecycle; the skill is choosing per job.
Plan & Design: Before You Drag an Element
Automation follows the same lifecycle as code: Plan → Build (in a sandbox) → Test → Debug → Deploy → Monitor. Most Flow problems — recursive loops, colliding automations, hard-to-debug logic — are planning failures, not tool failures.
Decision 1 — Flow, Apex, or Neither?
| Requirement | Right tool | Why |
|---|---|---|
| Block bad data on one object's own fields | Validation rule | Simplest thing that works wins |
| Set fields on the triggering record | Before-save record-triggered flow | Fastest automation on the platform — no extra DML |
| Create/update related records, notifications | After-save record-triggered flow | Declarative, admin-maintainable |
| Guided user interactions | Screen flow | The only declarative UI wizard |
| Complex branching + heavy volume + intricate error handling | Apex (often invoked from Flow) | Version control, unit tests, savepoints — see the Apex guide |
| Multi-user, multi-stage, long-running process | Flow Orchestration | Built for human hand-offs with work items |
Decision 2 — Where Does It Fit in the Save Order?
Record-triggered flows run inside the same save pipeline as triggers: before-save flows run before Apex before-triggers; after-save flows run after Apex after-triggers (and after workflow-era tools). If your org mixes Flow and Apex on one object, document who owns what — the cleanest split is "same-record field logic in before-save flows, cross-record logic in one Apex trigger OR one after-save flow, never both". The full pipeline is in the Apex guide's Plan & Design section.
Decision 3 — Automation Architecture per Object
- Keep counts low and purposes clear: a common convention is one before-save flow, one after-save flow, and optionally one per distinct business domain — each with tight entry conditions.
- Set Trigger Order (a field on the flow's start element, 1–2000) when order between multiple flows matters — never rely on alphabetical accident.
- Check what already exists first: Setup → Flow Trigger Explorer shows every flow that fires for a given object and event, in order. This is your pre-build reconnaissance tool.
- Name for the future:
Account — Before Save — Set Defaultstells the next admin everything;New Flow 7tells them nothing. Fill in the description on the flow AND on every element.
Worked Example: Planning "Renewal Opportunity Automation"
Requirement: when an Opportunity is Closed Won, create a renewal Opportunity dated a year out, unless one already exists.
- Tool: after-save record-triggered flow on Opportunity (creates a different record → can't be before-save).
- Entry condition:
StageName = 'Closed Won'with "only when a record is updated to meet the condition" — the flow fires on the transition to won, not on every later edit. This one checkbox is the recursion guard. - Dedupe: Get Records (renewal opp for same Account, stage = 'Renewal Pipeline') → Decision: found? end : create.
- Bulk check: Data Loader closing 200 opps → each interview runs its own Get Records; fine at this volume. If this were thousands nightly, reconsider as Apex.
- Test plan (see Testing): transition to won creates renewal · re-save of won opp creates nothing · existing renewal blocks duplicate · bulk update of 200.
- Deploy: build in sandbox → run flow tests → deploy via change set or CLI → activate → monitor Automation Event Logs the first week.
Sources: Salesforce Help — Flows · Record-Triggered Flows
Testing & Debugging Flows
Flows deserve the same testing discipline as Apex — and Salesforce keeps closing the tooling gap. Salesforce recently shipped a redesigned debug experience, and flow tests can now run alongside Apex tests in one run.
Debugging in Flow Builder
- Debug button: run the flow against real or sample inputs and watch each element execute with its inputs/outputs. For record-triggered flows, pick a triggering record and choose create/update simulation — rollback mode lets you debug without committing changes.
- Redesigned debug panel: a side-by-side debug + canvas view highlights the exact path taken, plus a dedicated Debug-Screen view for screen flows.
- Failed interview emails: unhandled flow errors email the admin (or a configured address) with the element-by-element story — read from the bottom up; the last element named is the one that failed.
- Automation Event Logs / Flow Interviews: Setup shows paused and failed interviews; resume or delete stuck ones after fixing the cause.
Flow Tests (Declarative Unit Tests)
Record-triggered flows support saved, rerunnable flow tests — the declarative sibling of Apex test methods:
- Create a test from a debug run (or from scratch): define the triggering record's initial values, the update that fires the flow, and assertions about outcomes ("resource X equals Y", "path taken was Z").
- Run all of a flow's tests from the Tests button before every new version activation.
- New: the Test Discovery API lets CI pipelines execute Apex tests and Flow tests in one run, with results in Setup's Application Test Execution — automation logic is finally first-class in CI (see the Apex guide's DevOps section for the pipeline itself).
- Current scope worth knowing: flow tests target record-triggered flows (create/update triggers) — screen flows still rely on debug runs and end-to-end testing (or UI test tools).
A Minimal Test Suite for the Renewal Flow
| Test | Initial record | Action | Assert |
|---|---|---|---|
| Creates renewal on win | Opp, stage = Negotiation | Update stage → Closed Won | Renewal opp created; CloseDate = today + 365 |
| No duplicate renewal | Won opp whose Account already has a renewal | Edit unrelated field | Path taken = "end (found existing)" |
| Ignores non-won saves | Opp, stage = Proposal | Update Amount | Flow's entry conditions not met — no run |
Debugging Checklist When a Flow Misbehaves
- Reproduce in Debug with the same record — the highlighted path usually answers it.
- Entry conditions: is the flow even starting? (Flow Trigger Explorer + debug logs show flow invocations.)
- Check which version is active — editing creates a new draft; users still run the old active version until you activate.
- Fault emails mention another object? Look for automation chains: your flow updated record B, whose own flow failed.
- For deep dives, debug logs record flow element execution alongside Apex — the same logs covered in the Apex guide.
Sources: Salesforce Help — Flow Tests · Salesforce Admins — Flow release features (official blog)
Flow Performance
Flows share transaction limits with Apex, and record-triggered flows add up fast on busy objects. Performance tuning in Flow is mostly about doing less, earlier.
The Performance Hierarchy
- 1. Entry conditions first: the cheapest flow run is the one that never starts. Tight entry conditions (with "updated to meet the condition") can cut a flow's executions by 95%+ on frequently edited objects.
- 2. Before-save when possible: Fast Field Updates run roughly 10× faster than after-save flows for same-record changes and don't consume extra DML.
- 3. Async for slow work: callouts, big related-record fan-outs, and anything a user shouldn't wait on belong on the Run Asynchronously path — same idea as Queueable Apex.
- 4. Batch smartly in scheduled flows: The new batch-size control lets heavy per-record work run in smaller transactions instead of failing at 200.
- 5. No DML/queries in loops — ever: the collection-then-commit pattern from Best Practices is the biggest saver.
Where Flows Hit Limits
| Limit (per transaction unless noted) | Value | Flow element that consumes it |
|---|---|---|
| SOQL queries | 100 | Get Records (each one) |
| DML statements | 150 | Create / Update / Delete Records (each element execution) |
| Executed elements at runtime | 2,000 | Every element, including each loop iteration |
| CPU time | 10s sync / 60s async | Formulas, loops, assignments |
| Schedule-triggered records / 24h | 250,000+ (license-based) | Scheduled flow record scope |
| Paused/waiting interviews | org-wide cap | Wait elements, scheduled paths |
The 2,000-element limit is the flow-specific one: a loop over 700 records with 3 elements inside = 2,100 executions = crash. Fixes: filter earlier (Get Records conditions), use the Transform element instead of loop+assignment for collection reshaping, move the job to a scheduled flow (fresh limits per batch) or Apex.
Screen Flow Speed
- Fewer, richer screens beat many small ones — each screen transition is a server round trip.
- Use reactive screen components (fields reacting to other fields on the same screen) instead of splitting screens just to branch — this alone modernizes most older wizards.
- Defer Get Records until the branch that needs it; don't front-load every query on flow start.
Sources: Flow Limits and Considerations · Salesforce Release Notes
Build & Deploy: Flows in Your Pipeline
Flows are metadata (XML) like Apex classes — they belong in version control and deploy through the same pipeline (change sets, CLI, or DevOps Center — the full pipeline lives in the Apex guide's Build & Deploy section). Here's what's Flow-specific.
Versions and Activation
- Every save creates a new version; exactly one version can be active. Editing an active flow gives you a draft — users keep running the active version until you activate the new one.
- Deployed flows arrive as the latest version but activation depends on org settings: by default they deploy inactive, and you activate after verifying. The org preference "Deploy processes and flows as active" changes that for automated pipelines — if you enable it, your pipeline must run flow tests.
- The new version comparison makes pre-activation review real: diff the incoming version against the running one.
- Old versions pile up (there's a 50-version cap per flow) — prune stale versions as part of release hygiene.
CLI Commands for Flows
# Pull a flow into your project / Git
sf project retrieve start --metadata Flow:Account_Priority
# Deploy it (with your Apex tests, in one validated deploy)
sf project deploy start --source-dir force-app --test-level RunLocalTests
# Flows live at:
# force-app/main/default/flows/Account_Priority.flow-meta.xml
In Git, flow XML diffs are verbose but reviewable — element names and the <start> block (trigger config, entry conditions) are exactly what a reviewer should eyeball, the same way they'd review a trigger's events.
Release Checklist for Automation
- Flow tests green (and included in the CI run via the Test Discovery API where available).
- Version comparison reviewed against the currently active version.
- Flow Trigger Explorer checked in the target org — confirm trigger order with flows that already exist there.
- Entry conditions verified against production data patterns (a condition that's rare in sandbox may match half of production).
- Post-deploy step scripted: activate the new version (if not auto-activated) and spot-check the first real runs in Automation Event Logs.
- Rollback story: reactivating the previous version takes one click — know which version that is before release night.
Sources: Deploy Flows · Salesforce CLI
What's New in Flow
Flow gets more new features per release than any other platform tool. The staples you might have missed, then the verified 2025–26 timeline.
Modern Staples (GA in Recent Years — Use Them Now)
- HTTP Callout: call REST APIs from Flow with no Apex — configure once against a Named Credential, get typed outputs.
- Transform element: reshape collections (source → target mapping) without loop + assignment scaffolding.
- Repeater component: screen flows can collect multiple of something ("add another beneficiary") — previously impossible declaratively.
- Custom Error element: block saves with precise messages from record-triggered flows (the Flow
addError()). - Action Button on screens: run an autolaunched flow mid-screen and use its outputs reactively — search-as-you-type patterns without LWC.
- Reactive screen components: same-screen reactivity that collapsed multi-screen wizards into single smart screens.
Timeline of Recent Flow Changes
| When | Headline Flow changes |
|---|---|
| Earlier updates | Redesigned debug panel (side-by-side canvas + Debug-Screen view) · flow version comparison · Quick Resources in the resource picker · smoother canvas (zoom, auto-align, collapsible branches) · AI-assisted Decision element (natural-language outcome logic) · Data Table supports Apex-defined collections · access fields of a just-created record without re-query · Automation Event-Triggered flows (e.g., File Attach events) · screen-flow Preview Styles for Aura/LWR sites · Test Discovery API runs Apex + Flow tests together |
| Recent updates | Flow Orchestration becomes a standard feature (no usage caps) · Setup AI agent can troubleshoot user access and flow questions conversationally |
| Latest updates | Native Show Toast Message action · Create Agent element — add an Agentforce agent to the canvas (pairs with our Agentforce guide) · collapsible fault paths · redesigned validation panel (grouped error cards) · scheduled-flow batch-size control · new date operators (Is Today, Is Tomorrow, anniversaries) · Data Table lookup fields link to records · styling support for 11 more screen components |
Modernization Checklist for Older Automation
- Legacy automations still active in your org? Run Setup → Migrate to Flow — the retired tools get no fixes or investment.
- Loops doing collection reshaping → Transform element.
- Apex written only for a callout → HTTP Callout in Flow (keep Apex where retry/parsing logic is complex).
- Multi-screen wizards → collapse with reactive components + Action Buttons.
- Validation rules that need related-record checks → Custom Error element in a before-save flow.
- Record-triggered flows without entry conditions → add them; it's the #1 performance and recursion fix.
Sources: Salesforce Admins — Flow release features · Salesforce Release Notes (all releases) · Salesforce Release Notes
Screen Flow Deep Dive
Screen flows are the most-requested flow skill for a reason: they're how admins ship real user interfaces. This section goes past "add a screen" into the techniques that make screen flows feel like product, not paperwork.
Conditional Visibility: One Smart Screen Beats Five Dumb Ones
- Every component has visibility conditions ("show when {!isBusinessAccount} equals true") — combined with reactive components, fields appear and disappear as the user types, on one screen, no server round trip.
- The design shift: old flows branched to different screens per case; modern flows put one adaptive screen up and let visibility do the branching. Fewer screens = fewer clicks = happier users.
Validation: Field-Level and Screen-Level
- Component validation: each input's Validate section takes a formula (true = valid) plus the error message — e.g.
BEGINS({!Phone}, '+')with "Include the country code." - Cross-field checks: validate on the component whose message should display, referencing the other fields (
{!EndDate} >= {!StartDate}on End Date). - The order rule: validation fires when the user clicks Next — design the error text as instructions ("Enter a date after the start date"), not verdicts ("Invalid").
Extending Screens: Local Actions and Custom Components
- Custom LWC screen components handle the screens standard components can't (address autocomplete, signature pads) — the component contract is in the LWC guide's Flow Screens section.
- Local actions run client-side logic between screens with no server call — an LWC with a blank template that, say, reads the browser's geolocation and hands it to flow variables instantly.
Embedding Screen Flows Everywhere
| Where | How | Notes |
|---|---|---|
| Lightning page / utility bar | The standard Flow component in App Builder | Pass recordId as an input variable |
| Inside your own LWC | <lightning-flow flow-api-name="Case_Intake" .flowInputVariables={inputs} onstatuschange={handleStatus}> | Listen for FINISHED in onstatuschange to react when the flow completes |
| Experience Cloud | Flow component on site pages (Aura and LWR sites) | Guest-user flows demand the strictest security review; preview styles per site template before publishing |
| Quick actions & buttons | Flow-type quick action or a button URL | The classic "guided process from a record" pattern |
Layout: Multi-Column and Sections
- Section components give you up to four columns per row — group related fields side by side instead of one long scroll.
- Columns stack on narrow screens automatically; still, test on mobile — a four-column address block is desktop thinking.
Reusable Screens via Subflows
A screen-flow subflow can contain screens — build the "collect address" or "confirm identity" screen once as a subflow with input/output variables, and every parent flow reuses it. When the address format changes, you fix one flow.
Sources: Flows (Help) · lightning-flow (Component Reference)
Flow Orchestration: Multi-Step, Multi-User Processes
Single flows automate a moment; orchestrations automate a process — days long, crossing departments, mixing automated steps with human work items. Employee onboarding, deal-desk approval, claims intake: anything with "then it sits with the finance team" in the middle is orchestration territory. It's now a standard feature, so the only cost is learning it.
The Building Blocks
| Piece | What it is | Example |
|---|---|---|
| Orchestration | The whole process definition (record-triggered or autolaunched) | "New Hire Onboarding" |
| Stage | A phase; runs its steps, completes when its exit logic says so | "Provisioning", "Week One" |
| Interactive step | A screen flow assigned to a user as a work item on a record | "IT: assign laptop" appears in the IT queue |
| Background step | An autolaunched flow run automatically | "Create accounts, send welcome email" |
| Evaluation flow | Decides whether a stage/step's conditions are met | "All week-one tasks done?" |
What You Get That Plain Flows Can't Do
- Work items: interactive steps land on the assigned user's record page / work guide with due dates — the process physically shows up in someone's queue instead of dying in an email.
- Parallelism: steps in a stage can run simultaneously (IT provisions while HR schedules) — a single flow would force artificial sequence.
- Long-running state: orchestrations wait days for humans without any Wait-element gymnastics; the run history shows exactly where every instance sits.
- Reuse: steps invoke ordinary screen flows and autolaunched flows — everything you've built in this guide becomes orchestration parts.
Design Rules from the Field
- Name stages after business phases, not mechanics ("Manager Review", not "Stage 2").
- Keep step flows small and single-purpose — orchestration is the coordinator; logic lives in the flows.
- Decide up front what happens to in-flight instances when you ship a new version — running orchestrations finish on the version they started on.
- Every interactive step needs an owner answer to: "what if they're on vacation?" (queues and reassignment beat named individuals).
Sources: Flows in Orchestrations (Help) · Interactive Steps (Help)
Flow Integration & Extensibility
Flow's superpower is being the orchestration layer that clicks into everything else: Apex when logic gets heavy, HTTP when data lives elsewhere, events when systems must react, agents when AI needs deterministic hands.
The Extensibility Menu
| Need | Mechanism | Deep dive |
|---|---|---|
| Complex server-side logic | Invocable Apex action | Apex Integration (bulkified example) |
| Client-side logic in screen flows | Local action (LWC) — no server call | Screen Flow Deep Dive |
| Call an external REST API, no code | HTTP Callout action on a Named Credential | Integration guide — Named Credentials |
| Import a whole API declaratively | External Services (OpenAPI spec → typed actions) | Integration guide — External Services |
| Tell other systems something happened | Publish a platform event (Create Records on the __e object) | Integration guide — Events |
| Human sign-off | Submit for Approval action / approval orchestrations | Below |
| Give an AI agent safe hands | Autolaunched flow as an Agentforce action | Agentforce guide |
Invocable LWC vs Invocable Apex: When Each
- Local action (LWC) when the work is client-side by nature: browser APIs (geolocation, clipboard), instant computation between screens, calling an API from the user's browser. Zero server latency; only exists inside screen flows.
- Invocable Apex when the work is server-side by nature: database logic, callouts with secrets (Named Credentials are server-side), anything a record-triggered or scheduled flow must also call.
- Tie-breaker: if it must run when no user is watching, it can't be a local action.
Publishing Platform Events from Flow
- A platform event is published with a plain Create Records element targeting the event object (
Order_Shipped__e) — set the fields, create, done. - Remember delivery semantics: events go out only if the transaction commits (default publish behavior), and subscribers must be idempotent — the design rules live in the Integration guide.
Flow + Approvals
- The Submit for Approval core action lets any flow push a record into an approval process — the classic pattern: record-triggered flow detects the condition, prepares fields, submits.
- Going forward, approvals themselves are becoming flows: approval orchestrations build multi-stage, multi-approver processes in Flow Builder — if you're designing a new approval matrix, start there rather than the classic engine (see Orchestration).
Sources: Flows (Help)
Flow Security: Running Context
Who a flow runs as decides what it can see and touch — and the default differs by flow type, which is why "it works for me" bugs and accidental data exposure both trace back to this section.
The Context Matrix
| Flow type | Default context | Meaning |
|---|---|---|
| Screen flow | User context | Runs with the running user's permissions, sharing and FLS — users can't see or edit through the flow what they couldn't otherwise |
| Record-triggered / scheduled / platform-event | System context | Runs as the "Automated Process" style context — it can touch what the automation needs regardless of the triggering user |
| Autolaunched (from Apex/REST) | Inherits the caller | Whatever context invoked it |
The Override Setting — and Its Sharp Edge
- Advanced settings let you force a flow to run in System Context With Sharing (ignores object/field permissions but respects record access) or System Context Without Sharing — Access All Data (ignores everything).
- With Sharing is the legitimate middle ground: e.g., a screen flow that must update a field the user can't edit directly, on records they can see.
- Without Sharing is the loaded weapon: any user who can run the flow effectively has admin-grade data access inside that flow's logic. Every use needs a written justification, tight entry conditions, and extra review — especially in Experience Cloud, where guest-user flows in system context have caused real-world data exposures.
Security Review Checklist for Flows
- Who can run it? (Profiles/permission sets for screen flows; "any record change" for triggered flows.)
- What context does it run in, and is every context override justified in the flow description?
- Guest-user reachable? Assume hostile inputs: validate everything, expose minimum fields, never trust a passed-in record Id without re-querying what the guest may see.
- Do fault paths leak? Error screens that echo raw fault messages can reveal internals — log the detail, show the user a generic message (Error Handling).
Capstone: One Business Process, Every Flow Skill
The finale assembles everything: a customer refund process for a subscription business — request intake, eligibility automation, finance approval, fulfillment, and monitoring. Four flow artifacts plus one Apex action, each doing the job it's best at.
1. The Architecture
| Artifact | Type | Job | Sections applied |
|---|---|---|---|
| Refund Request | Screen flow (Experience Cloud + internal) | Guided intake: order lookup, reason, amount — reactive screen, validation, reusable "verify identity" subflow screen | Screen Flows, Security (guest context!) |
| Refund Intake | Record-triggered flow on Refund_Request__c | Before-save defaults + after-save routing with entry conditions ("only when status becomes Submitted") | Record-Triggered, Performance |
| Refund Process | Orchestration | Stage 1: eligibility (background step) → Stage 2: finance review (interactive step, queue-assigned, only for amounts over threshold) → Stage 3: fulfillment (background) | Orchestration |
| Process Refund | Invocable Apex | The payment-gateway callout — retries, idempotency key, circuit breaker; too intricate for declarative HTTP | Apex Integration, Integration guide |
| Refund_Completed__e | Platform event from Flow | Tells the ERP and the data warehouse without coupling to either | Integrations |
2. The Decisions Worth Recording
- Why orchestration and not one big flow: the finance step waits on humans for up to three days — work items, reassignment and run-history visibility beat Wait-element loops (the exact trade-off from Orchestration).
- Why Apex for the gateway call: retry-with-backoff and idempotency keys are code-shaped problems; everything around them stays declarative — the boundary from Plan & Design's Flow-vs-Apex table.
- Eligibility as an autolaunched subflow: called by the orchestration and reusable by the future Agentforce refund agent — one eligibility truth (see the Agentforce guide's refund-guardrails pattern).
- Entry conditions everywhere: the record-triggered flow fires on the status transition only — the recursion guard and the performance win in one checkbox.
3. Reliability & Monitoring
- Every data element and the Apex action have fault connectors into the shared Log Error subflow (built in Autolaunched Flows), with a custom notification to the ops queue.
- Flow tests cover the record-triggered flow's four cases (submit, resubmit, non-qualifying edit, bulk load); the orchestration is verified in sandbox with a scripted end-to-end run before each release (Testing).
- Weekly review: failed-interview emails route to a queue, and a "Refund requests stuck > 3 days" report on the orchestration's run status is the process-health heartbeat.
- Deployment: all five artifacts travel in one package with versions documented; the rollback plan is "reactivate previous versions in reverse order" — written down before go-live (Deploy & DevOps).