Guides Salesforce Flow development: types, bulkification patterns, error handling, testing, subflows, and Flow vs Apex decisions. Use when building or reviewing Flows.
npx claudepluginhub jiten-singh-shahi/salesforce-claude-code --plugin salesforce-claude-codeThis skill uses the workspace's default tool permissions.
Procedures for building, testing, and maintaining Salesforce Flows. Flow type details, governor limits, bulkification rules, and the Flow vs Apex decision matrix live in the reference file.
Guides Salesforce Flow design and review: selects flow types (Record-Triggered, Screen, etc.), validates bulk safety (no DML/Get Records in loops), ensures fault handling and automation density checks.
Outlines best practices for Salesforce Flow Orchestrator (2025) to build multi-user, multi-stage workflows with approvals, fault paths, and no-code automation.
Provides patterns for Salesforce platform development: Lightning Web Components (LWC), Apex triggers/classes, REST/Bulk APIs, Connected Apps, Salesforce DX with scratch orgs and 2GP.
Share bugs, ideas, or general feedback.
Procedures for building, testing, and maintaining Salesforce Flows. Flow type details, governor limits, bulkification rules, and the Flow vs Apex decision matrix live in the reference file.
@../_reference/FLOW_PATTERNS.md
Flow: ACC_SetAccountPriority (Before Save, Account, before insert OR before update)
Entry Condition: {!$Record.AnnualRevenue} >= 1000000
Steps:
1. Assignment: {!$Record.Priority__c} = "High"
2. Assignment: {!$Record.Tier__c} = "Enterprise"
Notes:
- No Get Records, Update Records, or Create Records elements allowed
- No DML of any kind
- Very fast — runs in memory before DB write
Flow: OPP_CreateNegotiationTask (After Save, Opportunity, after update)
Entry Condition: {!$Record.StageName} = "Negotiation"
AND {!$Record.StageName} <> {!$Record__Prior.StageName}
Steps:
1. Get Records: User WHERE Id = {!$Record.OwnerId}
2. Create Records: Task (
Subject = "Review negotiation checklist"
WhatId = {!$Record.Id}
OwnerId = {!$Record.OwnerId}
ActivityDate = TODAY() + 3
Priority = "High"
)
Need to update the SAME record's fields?
-> Before Save (no DML counted, faster)
Note: Before Save flows cannot use Get Records or DML elements,
but CAN access parent fields via cross-object formula references
(e.g., {!$Record.Account.Name}).
Need to create/update OTHER records?
-> After Save (can do DML on other objects)
Need to send emails or call external services?
-> After Save (outbound actions need committed record)
BAD:
Loop: For each Contact in {!Contacts}
|
+-> Update Records: Contact <- DML inside loop = 1 DML per record
GOOD:
Loop: For each Contact in {!Contacts}
|
+-> Assignment: Add to contactsToUpdate collection
Update Records: {!contactsToUpdate} <- Single DML for entire collection
BAD:
Loop: For each Opportunity in {!Opportunities}
|
+-> Get Records: Account WHERE Id = {!loopVar.AccountId} <- SOQL per record
GOOD:
Get Records: Account WHERE Id IN {!opportunityAccountIds} <- single query
Loop: For each Opportunity in {!Opportunities}
|
+-> (Use data from pre-fetched collection, no SOQL)
Heap warning: If pre-fetch returns 10K+ records, the collection may
exceed the heap size limit (see @../_reference/GOVERNOR_LIMITS.md). Filter aggressively, or move to Batch Apex.
Parent Flow: SCR_CustomerOnboarding (Screen Flow)
|
+-- Subflow: VAL_ValidateAddress (Autolaunched)
| Input: {!streetAddress}, {!city}, {!state}
| Output: {!isValidAddress}, {!normalizedAddress}
|
+-- Subflow: INT_CreateCRMAccount (Autolaunched)
| Input: {!accountData}
| Output: {!newAccountId}
|
+-- Subflow: NOT_SendWelcomeEmail (Autolaunched)
Input: {!accountId}, {!contactEmail}
Variables passed between parent and subflow must be marked as available for input/output in the subflow definition.
Every element that can fail should have a fault connector.
[Update Records: Update Account]
|
+-(SUCCESS)-> [Next Step]
|
+-(FAULT)-> [Assignment: errorMessage =
"Failed: " + {!$Flow.FaultMessage}]
|
+-> [Screen: Display Error to User]
OR
+-> [Create Records: Error_Log__c]
OR
+-> [Custom Notification: Notify Admin]
Element: Get Records
Object: Contact
Filter: AccountId = {!$Record.Id} AND IsActive__c = true
Store All Records: No (when you need just one) / Yes (for a collection)
Tips:
- Add filter conditions to reduce records returned
- Select only the fields you need
- Use "Only the first record" when you need a single result
- Filter on indexed fields when possible (Id, OwnerId, ExternalId__c)
Formula Resource:
Name: FormattedMessage
Data Type: Text
Value: {!$Label.Welcome_Message} & " " & {!ContactRecord.FirstName}
Get Records:
Object: Service_Config__mdt
Filter: DeveloperName = "Production"
Fields: Endpoint_URL__c, Timeout_Ms__c
@IsTest
public class OppNegotiationFlowTest {
@TestSetup
static void setup() {
Account acc = TestDataFactory.createAccount('Test Account');
insert acc;
}
@IsTest
static void testNegotiationTask_stageChanged_createsTask() {
Account acc = [SELECT Id FROM Account LIMIT 1];
Opportunity opp = new Opportunity(
Name = 'Test Opp',
AccountId = acc.Id,
StageName = 'Prospecting',
CloseDate = Date.today().addDays(30),
Amount = 50000
);
insert opp;
Test.startTest();
opp.StageName = 'Negotiation';
update opp;
Test.stopTest();
List<Task> tasks = [SELECT Subject, Priority
FROM Task WHERE WhatId = :opp.Id];
System.assertEquals(1, tasks.size());
System.assertEquals('Review negotiation checklist', tasks[0].Subject);
}
@IsTest
static void testNegotiationTask_bulk_createsTasksForAll() {
Account acc = [SELECT Id FROM Account LIMIT 1];
List<Opportunity> opps = new List<Opportunity>();
for (Integer i = 0; i < 200; i++) {
opps.add(new Opportunity(
Name = 'Bulk Opp ' + i,
AccountId = acc.Id,
StageName = 'Prospecting',
CloseDate = Date.today().addDays(30),
Amount = 1000 * i
));
}
insert opps;
Test.startTest();
for (Opportunity opp : opps) { opp.StageName = 'Negotiation'; }
update opps;
Test.stopTest();
Integer taskCount = [SELECT COUNT() FROM Task WHERE WhatId IN :opps];
System.assertEquals(200, taskCount);
}
}
Five native Screen Flow components that eliminate the need for custom LWC in common patterns:
| Component | Best For |
|---|---|
| Kanban Board | Stage/status reassignment wizards, visual prioritization |
| Message | Confirmation prompts, warnings before destructive steps |
| File Preview | Document review steps in approval flows |
| Integrated Approval | Wizard-based approval flows where reps submit and track |
| Editable Data Table | Mass-edit child records within a guided wizard |
Record-Triggered Flows now support ContentVersion as a triggering object.
Object: ContentVersion
Trigger: A record is created or updated
Entry Conditions:
- {!$Record.FileExtension} = 'pdf'
- {!$Record.Title} Does NOT Contain 'DRAFT'
Use cases:
- Auto-tag documents based on filename patterns
- Notify a team when a contract document is uploaded
- Create audit log when a sensitive file type is uploaded
Orchestration Flows manage long-running, multi-step processes spanning hours or days.
Orchestration Flow: Employee_Onboarding
+-- Stage 1: "System Setup"
| +-- Background Step: Create user account (Autolaunched Flow)
| +-- Background Step: Provision email (Autolaunched Flow)
+-- Stage 2: "HR Review"
| +-- Interactive Step: Complete onboarding form (Screen Flow -> HR Manager)
+-- Stage 3: "Equipment & Access"
| +-- Interactive Step: Order equipment (Screen Flow -> IT Team queue)
| +-- Background Step: Grant system permissions (Autolaunched Flow)
+-- Stage 4: "Orientation"
+-- Interactive Step: Schedule orientation (Screen Flow -> Employee)
Each Flow has:
- Multiple versions (v1, v2, v3...)
- Only ONE active version at a time
- Inactive versions can be tested without activating
Deployment:
- Deploying creates a new version
- Set status: Active in Flow metadata to auto-activate:
<status>Active</status>
sf project deploy start \
--metadata "Flow:OPP_CreateNegotiationTask" \
--target-org myOrg
1. IDENTIFY — List all active Process Builders
sf data query -q "SELECT Id, MasterLabel, ProcessType FROM Flow
WHERE ProcessType = 'Workflow' AND Status = 'Active'" --json
2. ANALYZE — Document trigger object, criteria, and actions
3. CREATE — Build equivalent Record-Triggered Flow:
- Before Save Flow for field updates
- After Save Flow for create records, email alerts
4. TEST — Deploy to sandbox, test with bulk data (200+ records)
5. DEACTIVATE — Turn off Process Builder, monitor 1-2 weeks
6. CLEANUP — Delete via destructiveChanges.xml
sf-flow-agent -- for interactive, in-depth guidance