
Sf Flow
- 42 installs
- 12 repo stars
- Updated July 14, 2026
- clientell-ai/salesforce-skills
sf-flow is an agent skill that supplies Salesforce Flow metadata XML examples for elements like Assignment and collection updates.
About
sf-flow is a reference agent skill for Salesforce Flow development expressed as valid Flow metadata XML. It documents elements such as Assignment with operators (Assign, Add), assignment from record fields via elementReference, and patterns for adding items to collections, each with connector hooks to the next element. Solo builders and small teams extending Salesforce for CRM, RevOps, or custom SaaS on the platform can invoke this skill when their agent must generate or review flow XML instead of hand-waving Admin UI clicks. The readme is structured as a technical cookbook rather than a business methodology, so it pairs best with an org where you deploy flows as metadata in source control.
- Complete Flow elements reference in metadata XML format
- Assignment element examples: Assign, Add, elementReference from records
- Collection addition patterns for flow variables
- Connector targetReference wiring between elements
- Copy-paste XML aligned with Salesforce Flow metadata conventions
Sf Flow by the numbers
- 42 all-time installs (skills.sh)
- Ranked #3,272 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/clientell-ai/salesforce-skills --skill sf-flowAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 42 |
|---|---|
| repo stars | ★ 12 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 14, 2026 |
| Repository | clientell-ai/salesforce-skills ↗ |
What it does
Author valid Salesforce Flow metadata XML—including Assignment and collection patterns—while building automations on the platform.
Who is it for?
Best when you're shipping Salesforce automations and manage flows in XML or CI-deployed metadata.
Skip if: Non-Salesforce stacks, or admins who only use Flow Builder UI with no metadata/XML workflow.
When should I use this skill?
You are building or editing Salesforce Flows and need valid metadata XML for Assignment and related elements.
What you get
You get correct, connector-linked Flow XML snippets your agent can embed in Salesforce metadata projects or reviews.
- Flow XML fragments for assignments and collections
- Connector-linked element blocks ready for metadata merge
Files
Flow Generator & Process Builder Migrator
You are a Salesforce Flow specialist. Generate valid .flow-meta.xml files and migrate Process Builders to optimized Flows.
Flow Best Practices
Architecture Rules
- Maximum 3 record-triggered flows per object (before-save, after-save, before-delete)
- Use a Custom Permission bypass mechanism for all record-triggered flows
- Consolidate Process Builder logic — do NOT create 1:1 naive conversions
- Use subflows for reusable logic
- Use fault connectors on all DML and callout elements
Bypass Pattern
Every record-triggered flow should start with a Decision element checking:
<decisions>
<name>Check_Bypass</name>
<label>Check Bypass</label>
<defaultConnector>
<targetReference>Main_Logic</targetReference>
</defaultConnector>
<defaultConnectorLabel>Continue</defaultConnectorLabel>
<rules>
<name>Is_Bypassed</name>
<conditionLogic>or</conditionLogic>
<conditions>
<leftValueReference>$Permission.Bypass_Automation</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<booleanValue>true</booleanValue>
</rightValue>
</conditions>
<label>Bypassed</label>
</rules>
</decisions>Flow Types
1. Record-Triggered Flow (replaces Process Builder + Workflow Rules)
before save— field updates (no DML needed, most efficient)after save— related record updates, callouts, platform eventsbefore delete— validation, cascade operations
2. Screen Flow — user-facing wizards, guided processes 3. Autolaunched Flow — invoked by Apex, other flows, or platform events 4. Scheduled Flow — time-based batch operations
Flow XML Structure
<?xml version="1.0" encoding="UTF-8"?>
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>62.0</apiVersion>
<label>Account Before Save</label>
<processType>AutoLaunchedFlow</processType>
<triggerType>RecordBeforeSave</triggerType>
<objectType>Account</objectType>
<triggerOrder>1</triggerOrder>
<status>Active</status>
<!-- Elements go here -->
</Flow>Process Builder Migration
Migration Steps
1. Inventory: Read the Process Builder metadata from force-app/main/default/flows/ 2. Analyze: Identify all criteria nodes and actions 3. Consolidate: Group related PBs on same object into single flow 4. Generate: Create optimized Flow XML with:
- Bypass decision at entry
- Consolidated criteria as Decision elements
- Field updates as Assignment elements (before-save) or Record Update elements (after-save)
- Related record updates as Get + Update elements
5. Dependencies: Deploy Custom Permission and Custom Metadata first 6. Deploy: sf project deploy start -d force-app/main/default/flows/ 7. Verify: Confirm flow is active and PB is deactivated
Common PB → Flow Translations
| Process Builder | Flow Equivalent |
|---|---|
| Criteria Node | Decision Element |
| Field Update (same record) | Before-Save Assignment |
| Field Update (related record) | After-Save Get Records + Update Records |
| Create Record | After-Save Create Records |
| Email Alert | After-Save Action (Email Alert) |
| Post to Chatter | After-Save Create Records (FeedItem) |
| Invoke Apex | After-Save Action (Apex) |
| Scheduled Action | Scheduled Path on After-Save Flow |
Error Handling
- Add Fault connectors to every DML and callout element
- Fault paths should create a log record or send admin notification
- Use
$Flow.FaultMessageand$Flow.InterviewGuidin error logs
Complete Flow Types
1. Record-Triggered — before save, after save, before delete 2. Screen Flow — user-facing wizards with screens, inputs, choices 3. Autolaunched — invoked by Apex, other flows, or REST API 4. Scheduled — time-based batch (up to 250K interviews/day) 5. Platform Event-Triggered — subscribes to Platform Events 6. Orchestration — multi-step approval/business processes with stages
Global Variables
| Variable | Description | Example |
|---|---|---|
$Record | Triggering record (all fields) | {!$Record.Name} |
$Record__Prior | Previous field values | {!$Record__Prior.Status__c} |
$Api | Session/server info | {!$Api.Session_ID} |
$Organization | Org info | {!$Organization.Name} |
$Profile | Current user's profile | {!$Profile.Name} |
$User | Current user fields | {!$User.Email} |
$Flow | Runtime info | {!$Flow.FaultMessage} |
$Permission | Custom permission check | {!$Permission.Bypass_Automation} |
$Label | Custom labels | {!$Label.Error_Message} |
$Setup | Custom Metadata | {!$Setup.Config__mdt.Value__c} |
Screen Flow Elements
- Choice sets: Static choices, dynamic choices from SOQL, picklist choices
- Conditional visibility: Show/hide components based on conditions
- Stages: Multi-step progress indicator for guided flows
- Validation: Per-component and per-screen validation formulas
Collection Operations
- Loop: Iterate over collections with a loop variable
- Add to collection: Assignment element with Add operator
- Filter: Decision element inside loop to build filtered collections
Scheduled Paths
Replace Workflow time-based actions: add scheduled paths to after-save flows with time offsets (hours, days) relative to record field values.
Flow Test Coverage
- Flows now have test coverage tracking (FlowTestCoverage object)
- Create flow tests that exercise all decision branches
- Check coverage with:
SELECT FlowVersionId, NumElementsCovered, NumElementsNotCovered FROM FlowTestCoverage
Gotchas
- Flow interview limit: 250,000/day for scheduled flows — plan accordingly
- DML inside loops in flows hits governor limits just like Apex
$Recordchanges in before-save flows only commit when the record saves- Formula fields don't reflect changes made earlier in the same flow
- Scheduled flows run in system context — no WITH USER_MODE equivalent
- No native retry mechanism for failed callouts in flows
- Collection variables can consume significant memory with large datasets
- Subflow variable mapping must match types exactly — null/type mismatches cause runtime errors
- Custom permission checks are cached — recent changes may not reflect immediately
Workflow
1. If migrating: Read existing PB metadata with Glob/Read tools 2. Analyze requirements or existing automation logic 3. Generate .flow-meta.xml file(s) 4. Generate any required Custom Permission metadata 5. Deploy dependencies first, then flows 6. Verify Flow test coverage: query FlowTestCoverage to ensure all decision branches are exercised 7. Provide verification steps
References
- Flow Elements — complete XML reference for all element types, connectors, fault handling
- Global Variables — complete $Variable reference with all accessible fields
Flow Elements Reference (Metadata XML Format)
Complete reference for all Salesforce Flow elements with valid Flow metadata XML examples.
---
1. Assignment Element
Set variable values, add to collections, perform arithmetic.
<assignments>
<name>Set_Account_Variables</name>
<label>Set Account Variables</label>
<locationX>314</locationX>
<locationY>278</locationY>
<assignmentItems>
<!-- Set a simple variable -->
<assignToReference>varAccountName</assignToReference>
<operator>Assign</operator>
<value>
<stringValue>Default Account</stringValue>
</value>
</assignmentItems>
<assignmentItems>
<!-- Add to a number variable -->
<assignToReference>varTotalAmount</assignToReference>
<operator>Add</operator>
<value>
<numberValue>100.0</numberValue>
</value>
</assignmentItems>
<assignmentItems>
<!-- Assign from a record field -->
<assignToReference>varOwnerEmail</assignToReference>
<operator>Assign</operator>
<value>
<elementReference>Get_Account.Owner.Email</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
</assignments>Collection Addition
<assignments>
<name>Add_To_Collection</name>
<label>Add To Collection</label>
<locationX>314</locationX>
<locationY>398</locationY>
<assignmentItems>
<!-- Add a single record to a collection variable -->
<assignToReference>colAccounts</assignToReference>
<operator>Add</operator>
<value>
<elementReference>varCurrentAccount</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
</assignments>---
2. Decision Element
Branch logic with conditions, outcomes, and a default outcome.
<decisions>
<name>Check_Account_Rating</name>
<label>Check Account Rating</label>
<locationX>578</locationX>
<locationY>278</locationY>
<defaultConnector>
<targetReference>Handle_Default</targetReference>
</defaultConnector>
<defaultConnectorLabel>Default Outcome</defaultConnectorLabel>
<rules>
<name>Is_Hot</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>$Record.Rating</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>Hot</stringValue>
</rightValue>
</conditions>
<conditions>
<leftValueReference>$Record.AnnualRevenue</leftValueReference>
<operator>GreaterThan</operator>
<rightValue>
<numberValue>1000000.0</numberValue>
</rightValue>
</conditions>
<connector>
<targetReference>Handle_Hot_Account</targetReference>
</connector>
<label>Is Hot</label>
</rules>
<rules>
<name>Is_Warm</name>
<conditionLogic>or</conditionLogic>
<conditions>
<leftValueReference>$Record.Rating</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>Warm</stringValue>
</rightValue>
</conditions>
<connector>
<targetReference>Handle_Warm_Account</targetReference>
</connector>
<label>Is Warm</label>
</rules>
</decisions>Custom Condition Logic
<rules>
<name>Complex_Logic</name>
<!-- Custom logic: (1 AND 2) OR 3 -->
<conditionLogic>(1 AND 2) OR 3</conditionLogic>
<conditions>
<leftValueReference>$Record.Industry</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>Technology</stringValue>
</rightValue>
</conditions>
<conditions>
<leftValueReference>$Record.AnnualRevenue</leftValueReference>
<operator>GreaterThan</operator>
<rightValue>
<numberValue>500000.0</numberValue>
</rightValue>
</conditions>
<conditions>
<leftValueReference>$Record.Rating</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>Hot</stringValue>
</rightValue>
</conditions>
<connector>
<targetReference>Handle_Match</targetReference>
</connector>
<label>Complex Match</label>
</rules>---
3. Loop Element
Iterate over a collection, processing one item at a time.
<loops>
<name>Loop_Through_Contacts</name>
<label>Loop Through Contacts</label>
<locationX>578</locationX>
<locationY>518</locationY>
<collectionReference>Get_Contacts</collectionReference>
<iterationOrder>Asc</iterationOrder>
<nextValueConnector>
<targetReference>Update_Contact_Fields</targetReference>
</nextValueConnector>
<noMoreValuesConnector>
<targetReference>Update_All_Contacts</targetReference>
</noMoreValuesConnector>
</loops>The loop variable is automatically available as Loop_Through_Contacts (the element's API name) inside the loop body. Access fields with Loop_Through_Contacts.FieldName.
---
4. Get Records
Query records with filters, sorting, and field selection.
<recordLookups>
<name>Get_Related_Contacts</name>
<label>Get Related Contacts</label>
<locationX>314</locationX>
<locationY>518</locationY>
<assignNullValuesIfNoRecordsFound>true</assignNullValuesIfNoRecordsFound>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
<faultConnector>
<targetReference>Handle_Error</targetReference>
</faultConnector>
<filterLogic>and</filterLogic>
<filters>
<field>AccountId</field>
<operator>EqualTo</operator>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</filters>
<filters>
<field>Email</field>
<operator>IsNull</operator>
<value>
<booleanValue>false</booleanValue>
</value>
</filters>
<getFirstRecordOnly>false</getFirstRecordOnly>
<object>Contact</object>
<sortField>LastName</sortField>
<sortOrder>Asc</sortOrder>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordLookups>Get First Record Only (Storing Specific Fields)
<recordLookups>
<name>Get_Account_Owner</name>
<label>Get Account Owner</label>
<locationX>314</locationX>
<locationY>398</locationY>
<assignNullValuesIfNoRecordsFound>true</assignNullValuesIfNoRecordsFound>
<connector>
<targetReference>Decision_Element</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>Id</field>
<operator>EqualTo</operator>
<value>
<elementReference>$Record.OwnerId</elementReference>
</value>
</filters>
<getFirstRecordOnly>true</getFirstRecordOnly>
<object>User</object>
<queriedFields>Id</queriedFields>
<queriedFields>Email</queriedFields>
<queriedFields>ManagerId</queriedFields>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordLookups>---
5. Create Records
Insert new records with field value mappings.
Single Record
<recordCreates>
<name>Create_Task</name>
<label>Create Task</label>
<locationX>578</locationX>
<locationY>638</locationY>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
<faultConnector>
<targetReference>Handle_Error</targetReference>
</faultConnector>
<inputAssignments>
<field>Subject</field>
<value>
<stringValue>Follow Up</stringValue>
</value>
</inputAssignments>
<inputAssignments>
<field>WhoId</field>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Status</field>
<value>
<stringValue>Not Started</stringValue>
</value>
</inputAssignments>
<inputAssignments>
<field>ActivityDate</field>
<value>
<elementReference>$Flow.CurrentDate</elementReference>
</value>
</inputAssignments>
<object>Task</object>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordCreates>Multiple Records (from Collection Variable)
<recordCreates>
<name>Create_Multiple_Tasks</name>
<label>Create Multiple Tasks</label>
<locationX>578</locationX>
<locationY>758</locationY>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
<faultConnector>
<targetReference>Handle_Error</targetReference>
</faultConnector>
<inputReference>colTasksToCreate</inputReference>
</recordCreates>---
6. Update Records
Update records by filter criteria or from a record/collection variable.
Update by Filter Criteria
<recordUpdates>
<name>Update_Related_Opportunities</name>
<label>Update Related Opportunities</label>
<locationX>578</locationX>
<locationY>878</locationY>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
<faultConnector>
<targetReference>Handle_Error</targetReference>
</faultConnector>
<filterLogic>and</filterLogic>
<filters>
<field>AccountId</field>
<operator>EqualTo</operator>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</filters>
<filters>
<field>StageName</field>
<operator>EqualTo</operator>
<value>
<stringValue>Prospecting</stringValue>
</value>
</filters>
<inputAssignments>
<field>Description</field>
<value>
<stringValue>Account rating changed to Hot</stringValue>
</value>
</inputAssignments>
<object>Opportunity</object>
</recordUpdates>Update from a Collection Variable
<recordUpdates>
<name>Update_Contacts_Collection</name>
<label>Update Contacts Collection</label>
<locationX>578</locationX>
<locationY>998</locationY>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
<inputReference>colContactsToUpdate</inputReference>
</recordUpdates>---
7. Delete Records
Delete records matching filter criteria.
<recordDeletes>
<name>Delete_Old_Tasks</name>
<label>Delete Old Tasks</label>
<locationX>578</locationX>
<locationY>1118</locationY>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
<faultConnector>
<targetReference>Handle_Error</targetReference>
</faultConnector>
<filterLogic>and</filterLogic>
<filters>
<field>WhoId</field>
<operator>EqualTo</operator>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</filters>
<filters>
<field>Status</field>
<operator>EqualTo</operator>
<value>
<stringValue>Completed</stringValue>
</value>
</filters>
<object>Task</object>
</recordDeletes>Delete from a Collection Variable
<recordDeletes>
<name>Delete_Records_Collection</name>
<label>Delete Records Collection</label>
<locationX>578</locationX>
<locationY>1238</locationY>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
<inputReference>colRecordsToDelete</inputReference>
</recordDeletes>---
8. Screen Element
Build interactive UI screens with input components, validation, and conditional visibility.
<screens>
<name>Input_Screen</name>
<label>Input Screen</label>
<locationX>314</locationX>
<locationY>158</locationY>
<allowBack>true</allowBack>
<allowFinish>true</allowFinish>
<allowPause>false</allowPause>
<connector>
<targetReference>Process_Input</targetReference>
</connector>
<showFooter>true</showFooter>
<showHeader>true</showHeader>
<fields>
<name>Display_Text</name>
<fieldText><p>Please enter the account details below.</p></fieldText>
<fieldType>DisplayText</fieldType>
</fields>
<fields>
<name>Account_Name_Input</name>
<dataType>String</dataType>
<fieldText>Account Name</fieldText>
<fieldType>InputField</fieldType>
<isRequired>true</isRequired>
</fields>
<fields>
<name>Annual_Revenue_Input</name>
<dataType>Currency</dataType>
<fieldText>Annual Revenue</fieldText>
<fieldType>InputField</fieldType>
<isRequired>false</isRequired>
<scale>2</scale>
</fields>
<fields>
<name>Industry_Picklist</name>
<choiceReferences>Industry_Choices</choiceReferences>
<dataType>String</dataType>
<fieldText>Industry</fieldText>
<fieldType>DropdownBox</fieldType>
<isRequired>true</isRequired>
</fields>
<fields>
<name>Is_Priority</name>
<dataType>Boolean</dataType>
<fieldText>Is Priority Account?</fieldText>
<fieldType>InputField</fieldType>
</fields>
<!-- Conditional visibility -->
<fields>
<name>Priority_Reason</name>
<dataType>String</dataType>
<fieldText>Priority Reason</fieldText>
<fieldType>LargeTextArea</fieldType>
<visibilityRule>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>Is_Priority</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<booleanValue>true</booleanValue>
</rightValue>
</conditions>
</visibilityRule>
</fields>
<!-- Input validation -->
<fields>
<name>Email_Input</name>
<dataType>String</dataType>
<fieldText>Email Address</fieldText>
<fieldType>InputField</fieldType>
<validationRule>
<errorMessage>Please enter a valid email address.</errorMessage>
<formulaExpression>REGEX({!Email_Input}, "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}")</formulaExpression>
</validationRule>
</fields>
</screens>---
9. Action Element
Call Apex invocable actions, standard actions, or quick actions.
Apex Invocable Action
<actionCalls>
<name>Call_Apex_Action</name>
<label>Call Apex Action</label>
<locationX>578</locationX>
<locationY>1358</locationY>
<actionName>MyInvocableClass</actionName>
<actionType>apex</actionType>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
<faultConnector>
<targetReference>Handle_Error</targetReference>
</faultConnector>
<inputParameters>
<name>accountId</name>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</inputParameters>
<inputParameters>
<name>newRating</name>
<value>
<stringValue>Hot</stringValue>
</value>
</inputParameters>
<outputParameters>
<assignToReference>varResult</assignToReference>
<name>outputMessage</name>
</outputParameters>
<storeOutputAutomatically>true</storeOutputAutomatically>
</actionCalls>Send Email Action
<actionCalls>
<name>Send_Email_Alert</name>
<label>Send Email Alert</label>
<locationX>578</locationX>
<locationY>1478</locationY>
<actionName>emailSimple</actionName>
<actionType>emailSimple</actionType>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
<inputParameters>
<name>emailAddresses</name>
<value>
<elementReference>$Record.Owner.Email</elementReference>
</value>
</inputParameters>
<inputParameters>
<name>emailSubject</name>
<value>
<stringValue>Account Rating Changed</stringValue>
</value>
</inputParameters>
<inputParameters>
<name>emailBody</name>
<value>
<elementReference>varEmailBody</elementReference>
</value>
</inputParameters>
</actionCalls>Submit for Approval Action
<actionCalls>
<name>Submit_For_Approval</name>
<label>Submit For Approval</label>
<locationX>578</locationX>
<locationY>1598</locationY>
<actionName>submit</actionName>
<actionType>submit</actionType>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
<inputParameters>
<name>objectId</name>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</inputParameters>
<inputParameters>
<name>comment</name>
<value>
<stringValue>Auto-submitted by flow</stringValue>
</value>
</inputParameters>
</actionCalls>---
10. Subflow Element
Call another flow, passing input and output variables.
<subflows>
<name>Call_Notification_Flow</name>
<label>Call Notification Flow</label>
<locationX>578</locationX>
<locationY>1718</locationY>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
<flowName>Send_Notification_Subflow</flowName>
<inputAssignments>
<name>inputRecordId</name>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<name>inputNotificationType</name>
<value>
<stringValue>AccountUpdate</stringValue>
</value>
</inputAssignments>
<outputAssignments>
<assignToReference>varNotificationResult</assignToReference>
<name>outputSuccess</name>
</outputAssignments>
</subflows>---
11. Wait Element
Pause flow execution until time-based or event-based conditions are met.
Time-Based Wait
<waits>
<name>Wait_For_Follow_Up</name>
<label>Wait For Follow Up</label>
<locationX>578</locationX>
<locationY>1838</locationY>
<defaultConnector>
<targetReference>Timeout_Handler</targetReference>
</defaultConnector>
<defaultConnectorLabel>Default (Timeout)</defaultConnectorLabel>
<waitEvents>
<name>Three_Days_Later</name>
<conditionLogic>and</conditionLogic>
<connector>
<targetReference>Send_Follow_Up_Email</targetReference>
</connector>
<eventType>AlarmEvent</eventType>
<inputParameters>
<name>AlarmTime</name>
<value>
<elementReference>varFollowUpDateTime</elementReference>
</value>
</inputParameters>
<inputParameters>
<name>TimeOffset</name>
<value>
<numberValue>72</numberValue>
</value>
</inputParameters>
<inputParameters>
<name>TimeOffsetUnit</name>
<value>
<stringValue>Hours</stringValue>
</value>
</inputParameters>
<label>Three Days Later</label>
</waitEvents>
</waits>Event-Based Wait (Platform Event)
<waits>
<name>Wait_For_Approval_Event</name>
<label>Wait For Approval Event</label>
<locationX>578</locationX>
<locationY>1958</locationY>
<defaultConnector>
<targetReference>Timeout_Handler</targetReference>
</defaultConnector>
<defaultConnectorLabel>Default</defaultConnectorLabel>
<waitEvents>
<name>Approval_Received</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>Approval_Received.Record_Id__c</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<elementReference>$Record.Id</elementReference>
</rightValue>
</conditions>
<connector>
<targetReference>Process_Approval</targetReference>
</connector>
<eventType>Approval_Event__e</eventType>
<label>Approval Received</label>
</waitEvents>
</waits>---
12. Stage Element
Define stages for guided visual processes (Screen Flows).
<stages>
<name>Stage_Account_Info</name>
<label>Account Information</label>
<isActive>true</isActive>
<stageOrder>1</stageOrder>
</stages>
<stages>
<name>Stage_Contact_Info</name>
<label>Contact Information</label>
<isActive>true</isActive>
<stageOrder>2</stageOrder>
</stages>
<stages>
<name>Stage_Review</name>
<label>Review & Submit</label>
<isActive>true</isActive>
<stageOrder>3</stageOrder>
</stages>Set the current stage via assignment:
<assignments>
<name>Set_Stage_To_Contact</name>
<label>Set Stage To Contact Info</label>
<locationX>314</locationX>
<locationY>518</locationY>
<assignmentItems>
<assignToReference>$Flow.CurrentStage</assignToReference>
<operator>Assign</operator>
<value>
<elementReference>Stage_Contact_Info</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Contact_Screen</targetReference>
</connector>
</assignments>---
13. Connector Syntax
Connectors define the flow's execution path between elements.
Standard Connector
<connector>
<targetReference>Next_Element_Name</targetReference>
</connector>Default Connector (on Decision/Wait)
<defaultConnector>
<targetReference>Default_Path_Element</targetReference>
</defaultConnector>
<defaultConnectorLabel>Default Outcome</defaultConnectorLabel>Fault Connector
<faultConnector>
<targetReference>Error_Handler_Element</targetReference>
</faultConnector>Next Value Connector (on Loop)
<nextValueConnector>
<targetReference>Process_Current_Item</targetReference>
</nextValueConnector>No More Values Connector (on Loop)
<noMoreValuesConnector>
<targetReference>After_Loop_Element</targetReference>
</noMoreValuesConnector>Schedule Connector (on Start element for scheduled flows)
<scheduledPaths>
<name>Run_Immediately</name>
<connector>
<targetReference>First_Element</targetReference>
</connector>
<label>Run Immediately</label>
<offsetNumber>0</offsetNumber>
<offsetUnit>Hours</offsetUnit>
<timeSource>RecordTriggerEvent</timeSource>
</scheduledPaths>---
14. Platform Event-Triggered Flow
Complete XML for a flow triggered by a Platform Event.
<?xml version="1.0" encoding="UTF-8"?>
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>59.0</apiVersion>
<description>Processes incoming Order Events and creates tasks</description>
<interviewLabel>Order Event Handler {!$Flow.CurrentDateTime}</interviewLabel>
<label>Order Event Handler</label>
<processType>AutoLaunchedFlow</processType>
<status>Active</status>
<!-- Start element for Platform Event trigger -->
<start>
<locationX>50</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Check_Event_Status</targetReference>
</connector>
<object>Order_Event__e</object>
<triggerType>PlatformEvent</triggerType>
</start>
<decisions>
<name>Check_Event_Status</name>
<label>Check Event Status</label>
<locationX>314</locationX>
<locationY>158</locationY>
<defaultConnector>
<targetReference>Log_Other_Status</targetReference>
</defaultConnector>
<defaultConnectorLabel>Other Status</defaultConnectorLabel>
<rules>
<name>Is_Shipped</name>
<conditionLogic>and</conditionLogic>
<conditions>
<!-- Access event payload fields via $Record -->
<leftValueReference>$Record.Status__c</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>Shipped</stringValue>
</rightValue>
</conditions>
<connector>
<targetReference>Create_Shipping_Task</targetReference>
</connector>
<label>Is Shipped</label>
</rules>
</decisions>
<recordCreates>
<name>Create_Shipping_Task</name>
<label>Create Shipping Task</label>
<locationX>314</locationX>
<locationY>398</locationY>
<inputAssignments>
<field>Subject</field>
<value>
<elementReference>$Record.Order_Id__c</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Status</field>
<value>
<stringValue>Not Started</stringValue>
</value>
</inputAssignments>
<object>Task</object>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordCreates>
<assignments>
<name>Log_Other_Status</name>
<label>Log Other Status</label>
<locationX>578</locationX>
<locationY>398</locationY>
<assignmentItems>
<assignToReference>varLogMessage</assignToReference>
<operator>Assign</operator>
<value>
<elementReference>$Record.Status__c</elementReference>
</value>
</assignmentItems>
</assignments>
<variables>
<name>varLogMessage</name>
<dataType>String</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
</variables>
</Flow>---
15. Scheduled Flow
Complete XML with schedule/frequency configuration.
<?xml version="1.0" encoding="UTF-8"?>
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>59.0</apiVersion>
<description>Weekly cleanup of stale leads</description>
<interviewLabel>Stale Lead Cleanup {!$Flow.CurrentDateTime}</interviewLabel>
<label>Stale Lead Cleanup</label>
<processType>AutoLaunchedFlow</processType>
<status>Active</status>
<start>
<locationX>50</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Update_Stale_Lead</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>Status</field>
<operator>EqualTo</operator>
<value>
<stringValue>Open - Not Contacted</stringValue>
</value>
</filters>
<filters>
<field>LastModifiedDate</field>
<operator>LessThan</operator>
<value>
<elementReference>$Flow.CurrentDateTime</elementReference>
</value>
</filters>
<object>Lead</object>
<schedule>
<frequency>Weekly</frequency>
<startDate>2024-01-07</startDate>
<startTime>02:00:00.000Z</startTime>
</schedule>
<scheduledPaths>
<connector>
<targetReference>Update_Stale_Lead</targetReference>
</connector>
<pathType>AsyncAfterCommit</pathType>
</scheduledPaths>
<triggerType>Scheduled</triggerType>
</start>
<recordUpdates>
<name>Update_Stale_Lead</name>
<label>Update Stale Lead</label>
<locationX>314</locationX>
<locationY>158</locationY>
<inputAssignments>
<field>Status</field>
<value>
<stringValue>Closed - Not Converted</stringValue>
</value>
</inputAssignments>
<inputAssignments>
<field>Description</field>
<value>
<stringValue>Auto-closed by scheduled flow due to inactivity.</stringValue>
</value>
</inputAssignments>
<inputReference>$Record</inputReference>
</recordUpdates>
</Flow>---
16. Orchestration Flow
Step definitions and stage dependencies in an orchestration.
<?xml version="1.0" encoding="UTF-8"?>
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>59.0</apiVersion>
<label>Customer Onboarding Orchestration</label>
<processType>Orchestrator</processType>
<status>Active</status>
<start>
<locationX>50</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Stage_Data_Collection</targetReference>
</connector>
</start>
<!-- Orchestration Stage -->
<orchestratedStages>
<name>Stage_Data_Collection</name>
<label>Data Collection</label>
<locationX>314</locationX>
<locationY>158</locationY>
<connector>
<targetReference>Stage_Approval</targetReference>
</connector>
<stageSteps>
<name>Step_Collect_Info</name>
<actionName>Collect_Customer_Info_Screen_Flow</actionName>
<actionType>stepInteractive</actionType>
<assignees>
<assignee>
<elementReference>$Record.OwnerId</elementReference>
</assignee>
<assigneeType>User</assigneeType>
</assignees>
<inputParameters>
<name>recordId</name>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</inputParameters>
</stageSteps>
</orchestratedStages>
<!-- Dependent Stage -->
<orchestratedStages>
<name>Stage_Approval</name>
<label>Manager Approval</label>
<locationX>578</locationX>
<locationY>158</locationY>
<connector>
<targetReference>Stage_Provisioning</targetReference>
</connector>
<stageSteps>
<name>Step_Manager_Review</name>
<actionName>Manager_Approval_Screen_Flow</actionName>
<actionType>stepInteractive</actionType>
<assignees>
<assignee>
<elementReference>$Record.Owner.ManagerId</elementReference>
</assignee>
<assigneeType>User</assigneeType>
</assignees>
<entryConditions>
<leftValueReference>$Record.AnnualRevenue</leftValueReference>
<operator>GreaterThan</operator>
<rightValue>
<numberValue>100000.0</numberValue>
</rightValue>
</entryConditions>
</stageSteps>
</orchestratedStages>
<!-- Background Step Stage -->
<orchestratedStages>
<name>Stage_Provisioning</name>
<label>Provisioning</label>
<locationX>842</locationX>
<locationY>158</locationY>
<stageSteps>
<name>Step_Provision_Account</name>
<actionName>Provision_Account_Autolaunched_Flow</actionName>
<actionType>stepBackground</actionType>
</stageSteps>
</orchestratedStages>
</Flow>---
17. Screen Flow with Dynamic Choices
Query-based choice set for dynamic picklist values.
<!-- Dynamic Choice Set from SOQL -->
<dynamicChoiceSets>
<name>Account_Choices</name>
<dataType>String</dataType>
<displayField>Name</displayField>
<filterLogic>and</filterLogic>
<filters>
<field>Industry</field>
<operator>EqualTo</operator>
<value>
<stringValue>Technology</stringValue>
</value>
</filters>
<filters>
<field>IsActive__c</field>
<operator>EqualTo</operator>
<value>
<booleanValue>true</booleanValue>
</value>
</filters>
<object>Account</object>
<outputAssignments>
<assignToReference>varSelectedAccountId</assignToReference>
<field>Id</field>
</outputAssignments>
<sortField>Name</sortField>
<sortOrder>Asc</sortOrder>
<valueField>Id</valueField>
</dynamicChoiceSets>
<!-- Screen using the dynamic choice set -->
<screens>
<name>Select_Account_Screen</name>
<label>Select Account</label>
<locationX>314</locationX>
<locationY>158</locationY>
<allowFinish>true</allowFinish>
<connector>
<targetReference>Process_Selection</targetReference>
</connector>
<showFooter>true</showFooter>
<showHeader>true</showHeader>
<fields>
<name>Account_Dropdown</name>
<choiceReferences>Account_Choices</choiceReferences>
<dataType>String</dataType>
<fieldText>Select an Account</fieldText>
<fieldType>DropdownBox</fieldType>
<isRequired>true</isRequired>
</fields>
</screens>
<!-- Static choice definition for comparison -->
<choices>
<name>Choice_High</name>
<choiceText>High Priority</choiceText>
<dataType>String</dataType>
<value>
<stringValue>High</stringValue>
</value>
</choices>
<choices>
<name>Choice_Medium</name>
<choiceText>Medium Priority</choiceText>
<dataType>String</dataType>
<value>
<stringValue>Medium</stringValue>
</value>
</choices>
<choices>
<name>Choice_Low</name>
<choiceText>Low Priority</choiceText>
<dataType>String</dataType>
<value>
<stringValue>Low</stringValue>
</value>
</choices>---
18. Collection Variable Operations
Add, remove, and filter collections in assignment elements.
<!-- Define collection variables -->
<variables>
<name>colAccounts</name>
<dataType>SObject</dataType>
<isCollection>true</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
<objectType>Account</objectType>
</variables>
<variables>
<name>colFilteredAccounts</name>
<dataType>SObject</dataType>
<isCollection>true</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
<objectType>Account</objectType>
</variables>
<variables>
<name>varCurrentAccount</name>
<dataType>SObject</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
<objectType>Account</objectType>
</variables>
<!-- Add a record to a collection -->
<assignments>
<name>Add_Account_To_Collection</name>
<label>Add Account To Collection</label>
<locationX>314</locationX>
<locationY>278</locationY>
<assignmentItems>
<assignToReference>colAccounts</assignToReference>
<operator>Add</operator>
<value>
<elementReference>varCurrentAccount</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
</assignments>
<!-- Remove first matching item from collection -->
<assignments>
<name>Remove_From_Collection</name>
<label>Remove From Collection</label>
<locationX>314</locationX>
<locationY>398</locationY>
<assignmentItems>
<assignToReference>colAccounts</assignToReference>
<operator>RemoveFirst</operator>
<value>
<elementReference>varCurrentAccount</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
</assignments>
<!-- Remove all occurrences -->
<assignments>
<name>Remove_All_From_Collection</name>
<label>Remove All Matches</label>
<locationX>314</locationX>
<locationY>518</locationY>
<assignmentItems>
<assignToReference>colAccounts</assignToReference>
<operator>RemoveAll</operator>
<value>
<elementReference>varCurrentAccount</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
</assignments>
<!-- Remove all items (clear collection) by reassigning empty collection -->
<assignments>
<name>Clear_Collection</name>
<label>Clear Collection</label>
<locationX>314</locationX>
<locationY>638</locationY>
<assignmentItems>
<assignToReference>colAccounts</assignToReference>
<operator>RemoveAll</operator>
<value>
<elementReference>colAccounts</elementReference>
</value>
</assignmentItems>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
</assignments>
<!-- Collection Filter element (Spring '23+) -->
<collectionProcessors>
<name>Filter_Hot_Accounts</name>
<label>Filter Hot Accounts</label>
<locationX>578</locationX>
<locationY>278</locationY>
<collectionProcessorType>FilterCollectionProcessor</collectionProcessorType>
<collectionReference>colAccounts</collectionReference>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>colAccounts.Rating</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>Hot</stringValue>
</rightValue>
</conditions>
<connector>
<targetReference>Next_Element</targetReference>
</connector>
<outputReference>colFilteredAccounts</outputReference>
</collectionProcessors>---
19. Formula Element
Inline formula calculations used as flow resources.
<formulas>
<name>frmDaysUntilClose</name>
<dataType>Number</dataType>
<expression>{!$Record.CloseDate} - {!$Flow.CurrentDate}</expression>
<scale>0</scale>
</formulas>
<formulas>
<name>frmFullName</name>
<dataType>String</dataType>
<expression>{!$Record.FirstName} & " " & {!$Record.LastName}</expression>
</formulas>
<formulas>
<name>frmIsOverdue</name>
<dataType>Boolean</dataType>
<expression>{!$Record.CloseDate} < TODAY()</expression>
</formulas>
<formulas>
<name>frmDiscountedPrice</name>
<dataType>Currency</dataType>
<expression>IF(
{!$Record.AnnualRevenue} > 1000000,
{!varListPrice} * 0.80,
IF(
{!$Record.AnnualRevenue} > 500000,
{!varListPrice} * 0.90,
{!varListPrice}
)
)</expression>
<scale>2</scale>
</formulas>
<formulas>
<name>frmQuarterEnd</name>
<dataType>Date</dataType>
<expression>DATE(
YEAR(TODAY()),
CEILING(MONTH(TODAY()) / 3) * 3 + 1,
1
) - 1</expression>
</formulas>---
20. Fault Connector Pattern
Handle errors gracefully using $Flow.FaultMessage and $Flow.InterviewGuid for error logging.
<!-- DML operation with fault connector -->
<recordCreates>
<name>Create_Account</name>
<label>Create Account</label>
<locationX>314</locationX>
<locationY>158</locationY>
<connector>
<targetReference>Success_Path</targetReference>
</connector>
<faultConnector>
<targetReference>Log_Error</targetReference>
</faultConnector>
<inputAssignments>
<field>Name</field>
<value>
<elementReference>varAccountName</elementReference>
</value>
</inputAssignments>
<object>Account</object>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordCreates>
<!-- Error logging element using $Flow.FaultMessage -->
<recordCreates>
<name>Log_Error</name>
<label>Log Error</label>
<locationX>578</locationX>
<locationY>158</locationY>
<connector>
<targetReference>Error_Screen</targetReference>
</connector>
<inputAssignments>
<field>Error_Message__c</field>
<value>
<elementReference>$Flow.FaultMessage</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Flow_Interview_Id__c</field>
<value>
<elementReference>$Flow.InterviewGuid</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Flow_Name__c</field>
<value>
<stringValue>Account_Creation_Flow</stringValue>
</value>
</inputAssignments>
<inputAssignments>
<field>Record_Id__c</field>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Timestamp__c</field>
<value>
<elementReference>$Flow.CurrentDateTime</elementReference>
</value>
</inputAssignments>
<object>Flow_Error_Log__c</object>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordCreates>
<!-- Error screen for screen flows -->
<screens>
<name>Error_Screen</name>
<label>Error</label>
<locationX>842</locationX>
<locationY>158</locationY>
<allowFinish>true</allowFinish>
<showFooter>true</showFooter>
<showHeader>true</showHeader>
<fields>
<name>Error_Display</name>
<fieldText><p><b>An error occurred:</b></p>
<p>{!$Flow.FaultMessage}</p>
<p>Reference ID: {!$Flow.InterviewGuid}</p>
<p>Please contact your administrator with the reference ID above.</p></fieldText>
<fieldType>DisplayText</fieldType>
</fields>
</screens>Complete Fault Handling Strategy
<!-- Retry pattern: Set a counter and retry the DML -->
<variables>
<name>varRetryCount</name>
<dataType>Number</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
<scale>0</scale>
<value>
<numberValue>0</numberValue>
</value>
</variables>
<variables>
<name>varErrorOccurred</name>
<dataType>Boolean</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
<value>
<booleanValue>false</booleanValue>
</value>
</variables>
<!-- In fault handler, set error flag -->
<assignments>
<name>Set_Error_Flag</name>
<label>Set Error Flag</label>
<locationX>578</locationX>
<locationY>278</locationY>
<assignmentItems>
<assignToReference>varErrorOccurred</assignToReference>
<operator>Assign</operator>
<value>
<booleanValue>true</booleanValue>
</value>
</assignmentItems>
<assignmentItems>
<assignToReference>varRetryCount</assignToReference>
<operator>Add</operator>
<value>
<numberValue>1</numberValue>
</value>
</assignmentItems>
<connector>
<targetReference>Log_Error</targetReference>
</connector>
</assignments>Salesforce Flow Global Variables Reference
Complete reference for all global variables available in Salesforce Flows, with accessible fields and usage examples.
---
$Record
The triggering record in record-triggered flows. Contains all fields of the triggering SObject.
Available in: Record-Triggered Flows, Platform Event-Triggered Flows
Access pattern: $Record.FieldName
All Standard Fields (varies by object)
| Field | Description |
|---|---|
$Record.Id | Record ID |
$Record.Name | Record name |
$Record.OwnerId | Owner ID |
$Record.CreatedById | Creator user ID |
$Record.CreatedDate | Creation timestamp |
$Record.LastModifiedById | Last modifier user ID |
$Record.LastModifiedDate | Last modification timestamp |
$Record.RecordTypeId | Record type ID |
$Record.IsDeleted | Soft delete flag |
Traversing Relationships
Access parent fields via dot notation (up to 5 levels):
$Record.Account.Name
$Record.Account.Owner.Email
$Record.Account.Owner.Manager.Name
$Record.CreatedBy.Profile.NameUsage in Flow XML
<conditions>
<leftValueReference>$Record.Status</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>Closed Won</stringValue>
</rightValue>
</conditions>---
$Record__Prior
The previous values of the triggering record before the update. Only available in before-update and after-update record-triggered flows.
Available in: Record-Triggered Flows (Update context only)
Access pattern: $Record__Prior.FieldName
Field Change Detection Patterns
Compare current and prior values to detect specific field changes:
<!-- Detect Stage change -->
<conditions>
<leftValueReference>$Record.StageName</leftValueReference>
<operator>NotEqualTo</operator>
<rightValue>
<elementReference>$Record__Prior.StageName</elementReference>
</rightValue>
</conditions><!-- Detect change TO a specific value -->
<rules>
<name>Stage_Changed_To_Closed_Won</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>$Record.StageName</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>Closed Won</stringValue>
</rightValue>
</conditions>
<conditions>
<leftValueReference>$Record__Prior.StageName</leftValueReference>
<operator>NotEqualTo</operator>
<rightValue>
<stringValue>Closed Won</stringValue>
</rightValue>
</conditions>
<connector>
<targetReference>Handle_Closed_Won</targetReference>
</connector>
<label>Stage Changed To Closed Won</label>
</rules><!-- Detect Owner change -->
<conditions>
<leftValueReference>$Record.OwnerId</leftValueReference>
<operator>NotEqualTo</operator>
<rightValue>
<elementReference>$Record__Prior.OwnerId</elementReference>
</rightValue>
</conditions><!-- Detect value increase (e.g., Amount increased) -->
<conditions>
<leftValueReference>$Record.Amount</leftValueReference>
<operator>GreaterThan</operator>
<rightValue>
<elementReference>$Record__Prior.Amount</elementReference>
</rightValue>
</conditions>Use in Entry Conditions (Start Element)
<start>
<locationX>50</locationX>
<locationY>0</locationY>
<connector>
<targetReference>First_Element</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>StageName</field>
<operator>EqualTo</operator>
<value>
<stringValue>Closed Won</stringValue>
</value>
</filters>
<filters>
<field>StageName</field>
<operator>IsChanged</operator>
<value>
<booleanValue>true</booleanValue>
</value>
</filters>
<object>Opportunity</object>
<recordTriggerType>Update</recordTriggerType>
<triggerType>RecordAfterSave</triggerType>
</start>---
$Api
Session and endpoint information for the current API context.
Available in: All flow types
| Field | Type | Description |
|---|---|---|
$Api.Session_ID | String | Current session ID. Returns null in flows run without a session (scheduled, platform event). |
$Api.Enterprise_Server_URL | String | Enterprise SOAP API endpoint URL for the org. |
$Api.Partner_Server_URL | String | Partner SOAP API endpoint URL for the org. |
Usage Example
<!-- Pass session ID to an external callout via Apex action -->
<actionCalls>
<name>Call_External_Service</name>
<label>Call External Service</label>
<actionName>ExternalServiceAction</actionName>
<actionType>apex</actionType>
<inputParameters>
<name>sessionId</name>
<value>
<elementReference>$Api.Session_ID</elementReference>
</value>
</inputParameters>
<inputParameters>
<name>serverUrl</name>
<value>
<elementReference>$Api.Partner_Server_URL</elementReference>
</value>
</inputParameters>
</actionCalls>---
$Organization
Information about the current Salesforce org.
Available in: All flow types
| Field | Type | Description |
|---|---|---|
$Organization.Id | String | Organization ID (18-character) |
$Organization.Name | String | Organization name |
$Organization.City | String | City from company info |
$Organization.State | String | State/Province |
$Organization.Country | String | Country |
$Organization.PostalCode | String | Postal/ZIP code |
$Organization.Street | String | Street address |
$Organization.Phone | String | Main phone number |
$Organization.Fax | String | Fax number |
$Organization.DefaultLocaleSidKey | String | Default locale (e.g., en_US) |
$Organization.LanguageLocaleKey | String | Default language |
$Organization.TimeZoneSidKey | String | Default time zone |
$Organization.UiSkin | String | UI theme |
$Organization.InstanceName | String | Instance (e.g., NA135, CS42) |
$Organization.IsSandbox | Boolean | True if org is a sandbox |
$Organization.TrialExpirationDate | Date | Trial expiration (null if not trial) |
Usage Example
<!-- Branch logic based on sandbox vs production -->
<decisions>
<name>Check_Environment</name>
<label>Check Environment</label>
<defaultConnector>
<targetReference>Production_Logic</targetReference>
</defaultConnector>
<defaultConnectorLabel>Production</defaultConnectorLabel>
<rules>
<name>Is_Sandbox</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>$Organization.IsSandbox</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<booleanValue>true</booleanValue>
</rightValue>
</conditions>
<connector>
<targetReference>Sandbox_Logic</targetReference>
</connector>
<label>Is Sandbox</label>
</rules>
</decisions>---
$Profile
Current running user's profile information.
Available in: All flow types
| Field | Type | Description |
|---|---|---|
$Profile.Id | String | Profile ID |
$Profile.Name | String | Profile name (e.g., System Administrator, Standard User) |
Usage Example
<!-- Restrict action to System Administrators -->
<conditions>
<leftValueReference>$Profile.Name</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>System Administrator</stringValue>
</rightValue>
</conditions>---
$User
Current running user's information.
Available in: All flow types
| Field | Type | Description |
|---|---|---|
$User.Id | String | User ID |
$User.FirstName | String | First name |
$User.LastName | String | Last name |
$User.Email | String | Email address |
$User.Username | String | Username (email format) |
$User.ProfileId | String | Profile ID |
$User.UserRoleId | String | Role ID |
$User.ManagerId | String | Manager's user ID |
$User.Title | String | Title |
$User.CompanyName | String | Company name |
$User.Department | String | Department |
$User.Division | String | Division |
$User.Phone | String | Phone number |
$User.MobilePhone | String | Mobile phone |
$User.Alias | String | Alias |
$User.CommunityNickname | String | Community nickname |
$User.IsActive | Boolean | Active flag |
$User.TimeZoneSidKey | String | User time zone |
$User.LocaleSidKey | String | User locale |
$User.LanguageLocaleKey | String | User language |
$User.DefaultCurrency | String | User default currency (multi-currency orgs) |
$User.ContactId | String | Contact ID (community users) |
$User.AccountId | String | Account ID (community users) |
$User.SmallPhotoUrl | String | Small profile photo URL |
$User.FullPhotoUrl | String | Full profile photo URL |
Usage Examples
<!-- Assign task to current user's manager -->
<inputAssignments>
<field>OwnerId</field>
<value>
<elementReference>$User.ManagerId</elementReference>
</value>
</inputAssignments><!-- Send notification to the running user -->
<inputParameters>
<name>emailAddresses</name>
<value>
<elementReference>$User.Email</elementReference>
</value>
</inputParameters><!-- Check if running user is a community user -->
<conditions>
<leftValueReference>$User.ContactId</leftValueReference>
<operator>IsNull</operator>
<rightValue>
<booleanValue>false</booleanValue>
</rightValue>
</conditions>---
$Flow
Flow execution context information.
Available in: All flow types
| Field | Type | Description |
|---|---|---|
$Flow.CurrentDateTime | DateTime | Current date and time at the moment of evaluation |
$Flow.CurrentDate | Date | Current date (no time component) |
$Flow.CurrentStage | String | Active stage in a staged flow (Screen Flow with stages) |
$Flow.ActiveStages | Collection | Collection of active stage names |
$Flow.FaultMessage | String | Error message when a fault connector is followed. Only populated in fault paths. |
$Flow.InterviewGuid | String | Unique identifier for the current flow interview (execution instance) |
Usage Examples
<!-- Set a due date 7 days from now -->
<formulas>
<name>frmDueDate</name>
<dataType>Date</dataType>
<expression>{!$Flow.CurrentDate} + 7</expression>
</formulas><!-- Use in fault connector for error logging -->
<inputAssignments>
<field>Error_Message__c</field>
<value>
<elementReference>$Flow.FaultMessage</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Interview_GUID__c</field>
<value>
<elementReference>$Flow.InterviewGuid</elementReference>
</value>
</inputAssignments><!-- Navigate between stages -->
<assignments>
<name>Move_To_Review_Stage</name>
<label>Move To Review Stage</label>
<assignmentItems>
<assignToReference>$Flow.CurrentStage</assignToReference>
<operator>Assign</operator>
<value>
<elementReference>Stage_Review</elementReference>
</value>
</assignmentItems>
</assignments>---
$Permission
Check whether the running user has a specific Custom Permission.
Available in: All flow types
Access pattern: $Permission.CustomPermissionApiName (returns Boolean)
Usage Example
<!-- Check if user has a custom permission -->
<conditions>
<leftValueReference>$Permission.Can_Approve_Large_Deals</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<booleanValue>true</booleanValue>
</rightValue>
</conditions><!-- Gate a screen flow section behind a permission -->
<fields>
<name>Admin_Section</name>
<fieldText><p>Administrative Override Options</p></fieldText>
<fieldType>DisplayText</fieldType>
<visibilityRule>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>$Permission.Admin_Override_Access</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<booleanValue>true</booleanValue>
</rightValue>
</conditions>
</visibilityRule>
</fields>---
$Label
Access Custom Labels by their API name. Returns the label value in the running user's language.
Available in: All flow types
Access pattern: $Label.CustomLabelApiName (returns String)
Usage Example
<!-- Display a custom label in a screen -->
<fields>
<name>Welcome_Message</name>
<fieldText>{!$Label.Welcome_Message_Text}</fieldText>
<fieldType>DisplayText</fieldType>
</fields><!-- Use custom label as email subject -->
<inputParameters>
<name>emailSubject</name>
<value>
<elementReference>$Label.Notification_Email_Subject</elementReference>
</value>
</inputParameters><!-- Use in a formula -->
<formulas>
<name>frmLocalizedGreeting</name>
<dataType>String</dataType>
<expression>{!$Label.Greeting_Prefix} & " " & {!$User.FirstName}</expression>
</formulas>---
$Setup
Access Custom Metadata Type records and their field values.
Available in: All flow types
Access pattern: $Setup.CustomMetadataTypeName__mdt.RecordDeveloperName.FieldName__c
Note: This accesses Custom Metadata Type records without SOQL, and they do not count against query limits.
Usage Examples
<!-- Read a configuration value from Custom Metadata -->
<conditions>
<leftValueReference>$Setup.App_Config__mdt.Default.Is_Feature_Enabled__c</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<booleanValue>true</booleanValue>
</rightValue>
</conditions><!-- Use Custom Metadata value in an assignment -->
<assignmentItems>
<assignToReference>varMaxRetries</assignToReference>
<operator>Assign</operator>
<value>
<elementReference>$Setup.Integration_Settings__mdt.Default.Max_Retries__c</elementReference>
</value>
</assignmentItems><!-- Use in a formula -->
<formulas>
<name>frmApiEndpoint</name>
<dataType>String</dataType>
<expression>{!$Setup.Integration_Settings__mdt.Default.Base_URL__c} & "/api/v2/accounts"</expression>
</formulas>---
$System
System-level constants.
Available in: All flow types
| Field | Type | Description |
|---|---|---|
$System.OriginDateTime | DateTime | The literal value 1900-01-01 00:00:00. Used as a baseline for date/time arithmetic. |
Usage Example
<!-- Calculate minutes elapsed since a timestamp -->
<formulas>
<name>frmMinutesElapsed</name>
<dataType>Number</dataType>
<expression>({!$Flow.CurrentDateTime} - {!$Record.CreatedDate}) * 24 * 60</expression>
<scale>0</scale>
</formulas>
<!-- Use OriginDateTime as a sentinel/default value -->
<assignmentItems>
<assignToReference>varLastProcessedDate</assignToReference>
<operator>Assign</operator>
<value>
<elementReference>$System.OriginDateTime</elementReference>
</value>
</assignmentItems>---
$ContentDocument
Access document information in document-triggered flows (ContentDocument or ContentVersion triggers).
Available in: Record-Triggered Flows on ContentDocument or ContentVersion
| Field | Type | Description |
|---|---|---|
$Record.Title | String | Document title |
$Record.FileType | String | File extension (PDF, DOCX, etc.) |
$Record.ContentSize | Number | File size in bytes |
$Record.OwnerId | String | Owner of the document |
$Record.LatestPublishedVersionId | String | Latest ContentVersion ID |
$Record.ParentId | String | Parent record (when accessed via ContentDocumentLink) |
Usage Example (ContentVersion-triggered flow)
<start>
<locationX>50</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Check_File_Type</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>FileType</field>
<operator>EqualTo</operator>
<value>
<stringValue>PDF</stringValue>
</value>
</filters>
<object>ContentVersion</object>
<recordTriggerType>Create</recordTriggerType>
<triggerType>RecordAfterSave</triggerType>
</start>
<decisions>
<name>Check_File_Type</name>
<label>Check File Type</label>
<defaultConnector>
<targetReference>Skip_Processing</targetReference>
</defaultConnector>
<defaultConnectorLabel>Other Type</defaultConnectorLabel>
<rules>
<name>Is_PDF</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>$Record.FileType</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>PDF</stringValue>
</rightValue>
</conditions>
<conditions>
<leftValueReference>$Record.ContentSize</leftValueReference>
<operator>LessThan</operator>
<rightValue>
<numberValue>5242880</numberValue>
</rightValue>
</conditions>
<connector>
<targetReference>Process_PDF</targetReference>
</connector>
<label>Is PDF Under 5MB</label>
</rules>
</decisions>---
Common Patterns and Recipes
Pattern 1: Field Change Detection with Action
Detect when a specific field changes and perform an action only on that change:
<!-- Entry criteria: only run when Status changes -->
<start>
<connector>
<targetReference>Check_New_Status</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>Status__c</field>
<operator>IsChanged</operator>
<value>
<booleanValue>true</booleanValue>
</value>
</filters>
<object>Case</object>
<recordTriggerType>Update</recordTriggerType>
<triggerType>RecordAfterSave</triggerType>
</start>Pattern 2: Conditional Logic Based on User and Record
<decisions>
<name>Can_User_Modify</name>
<label>Can User Modify</label>
<defaultConnector>
<targetReference>Access_Denied_Screen</targetReference>
</defaultConnector>
<defaultConnectorLabel>No Access</defaultConnectorLabel>
<rules>
<name>Is_Owner_Or_Admin</name>
<conditionLogic>or</conditionLogic>
<conditions>
<leftValueReference>$Record.OwnerId</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<elementReference>$User.Id</elementReference>
</rightValue>
</conditions>
<conditions>
<leftValueReference>$Profile.Name</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>System Administrator</stringValue>
</rightValue>
</conditions>
<conditions>
<leftValueReference>$Permission.Override_Record_Access</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<booleanValue>true</booleanValue>
</rightValue>
</conditions>
<connector>
<targetReference>Allow_Modification</targetReference>
</connector>
<label>Is Owner or Admin</label>
</rules>
</decisions>Pattern 3: Environment-Aware Configuration
<!-- Use Custom Metadata for environment-specific config -->
<formulas>
<name>frmApiUrl</name>
<dataType>String</dataType>
<expression>IF(
{!$Organization.IsSandbox},
{!$Setup.API_Config__mdt.Sandbox.Endpoint_URL__c},
{!$Setup.API_Config__mdt.Production.Endpoint_URL__c}
)</expression>
</formulas>Pattern 4: Error Handling with Context
<!-- Comprehensive error logging with all context variables -->
<recordCreates>
<name>Create_Error_Log</name>
<label>Create Error Log</label>
<inputAssignments>
<field>Error_Message__c</field>
<value>
<elementReference>$Flow.FaultMessage</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Interview_Id__c</field>
<value>
<elementReference>$Flow.InterviewGuid</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Running_User__c</field>
<value>
<elementReference>$User.Id</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>User_Profile__c</field>
<value>
<elementReference>$Profile.Name</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Org_Id__c</field>
<value>
<elementReference>$Organization.Id</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Is_Sandbox__c</field>
<value>
<elementReference>$Organization.IsSandbox</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Timestamp__c</field>
<value>
<elementReference>$Flow.CurrentDateTime</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<field>Record_Id__c</field>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</inputAssignments>
<object>Flow_Error_Log__c</object>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordCreates>Pattern 5: Multi-Field Change Detection Formula
<!-- Formula to detect any of several fields changing -->
<formulas>
<name>frmKeyFieldsChanged</name>
<dataType>Boolean</dataType>
<expression>OR(
{!$Record.Amount} != {!$Record__Prior.Amount},
{!$Record.StageName} != {!$Record__Prior.StageName},
{!$Record.CloseDate} != {!$Record__Prior.CloseDate},
{!$Record.OwnerId} != {!$Record__Prior.OwnerId}
)</expression>
</formulas>
<!-- Use the formula in a decision -->
<decisions>
<name>Did_Key_Fields_Change</name>
<label>Did Key Fields Change</label>
<defaultConnector>
<targetReference>Skip_Notification</targetReference>
</defaultConnector>
<defaultConnectorLabel>No Changes</defaultConnectorLabel>
<rules>
<name>Key_Fields_Changed</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>frmKeyFieldsChanged</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<booleanValue>true</booleanValue>
</rightValue>
</conditions>
<connector>
<targetReference>Send_Change_Notification</targetReference>
</connector>
<label>Key Fields Changed</label>
</rules>
</decisions>Pattern 6: Using $Label for Multi-Language Support
<!-- Screen with localized labels -->
<screens>
<name>Localized_Screen</name>
<label>Localized Screen</label>
<fields>
<name>Header_Text</name>
<fieldText>{!$Label.Screen_Header}</fieldText>
<fieldType>DisplayText</fieldType>
</fields>
<fields>
<name>Name_Input</name>
<dataType>String</dataType>
<fieldText>{!$Label.Name_Field_Label}</fieldText>
<fieldType>InputField</fieldType>
<isRequired>true</isRequired>
<validationRule>
<errorMessage>{!$Label.Name_Required_Error}</errorMessage>
<formulaExpression>LEN({!Name_Input}) > 0</formulaExpression>
</validationRule>
</fields>
</screens>Related skills
How it compares
Use as a Flow XML snippet reference, not as a substitute for Salesforce’s full element catalog or org-specific governor-limit testing.
FAQ
Who is sf-flow for?
Developers and Salesforce implementers who author or review Flow metadata XML with AI coding agents.
When should I use sf-flow?
Use during Build while creating assignments, variable math, record field copies, and collection updates inside Salesforce Flows.
Is sf-flow safe to install?
It is documentation-only XML patterns—review the Security Audits panel on this page and always validate flows in a sandbox before production deploy.