Subflow Code Examples

Overview

Subflows extract logical chunks into reusable components that can be called from multiple Flows or Apex. These examples demonstrate common patterns for:

When to Use

Use Subflows When

Avoid Subflows When

Example 1: Reusable Task Creation

Use Case: Create a standardized follow-up task that can be reused across multiple Flows.

Subflow Name: Subflow_Create_Follow_Up_Task

Input Variables:

Output Variables:

Subflow Structure:

  1. Start Element: Subflow
    • Input Variables: All listed above
    • Output Variables: All listed above
  2. Assignment Element: Set Default Values
    • TaskPriority = IF(ISBLANK(TaskPriority), 'Medium', TaskPriority)
    • DaysUntilDue = IF(ISBLANK(DaysUntilDue), 7, DaysUntilDue)
  3. Get Records Element: Get Record Owner (if not assigned)
    • Object: Record (dynamic based on RelatedRecordId)
    • Filter: Id = {!RelatedRecordId}
    • Store In: RelatedRecord (single record variable)
    • Get Fields: OwnerId
  4. Decision Node: Check Assignment
    • Outcome 1: ISBLANK(AssignedToUserId) → Use Record Owner
    • Outcome 2: NOT(ISBLANK(AssignedToUserId)) → Use Assigned User
  5. Assignment Element: Set Assignment
    • FinalOwnerId = IF(ISBLANK(AssignedToUserId), RelatedRecord.OwnerId, AssignedToUserId)
  6. Create Records Element: Create Task
    • Object: Task
    • How Many: One
    • Fields:
      • Subject = {!TaskSubject}
      • WhatId = {!RelatedRecordId}
      • Status = 'Not Started'
      • Priority = {!TaskPriority}
      • OwnerId = {!FinalOwnerId}
      • ActivityDate = TODAY() + {!DaysUntilDue}
    • Store In: NewTask (single record variable)
    • Fault Path: Set error and continue
  7. Decision Node: Check Success
    • Outcome 1: NewTask.Id != null → Success Path
    • Outcome 2: Default → Error Path
  8. Assignment Element: Set Success Output
    • CreatedTaskId = {!NewTask.Id}
    • IsSuccess = true
    • ErrorMessage = ''
  9. Assignment Element: Set Error Output
    • CreatedTaskId = ''
    • IsSuccess = false
    • ErrorMessage = 'Failed to create task: ' & {!$Flow.FaultMessage}
  10. End Element: End Subflow
    • Return: Output variables

Usage in Parent Flow:

Call Subflow: Create Follow-Up Task
  Input:
    RelatedRecordId = {!$Record.Id}
    TaskSubject = 'Follow up on Case ' & {!$Record.CaseNumber}
    TaskPriority = {!$Record.Priority}
    DaysUntilDue = 3
  Output:
    CreatedTaskId → TaskId variable
    IsSuccess → TaskCreatedSuccessfully variable

Key Points:

Example 2: Reusable Status Update

Use Case: Update related records’ status when parent record status changes.

Subflow Name: Subflow_Update_Related_Records_Status

Input Variables:

Output Variables:

Subflow Structure:

  1. Start Element: Subflow
    • Input Variables: All listed above
    • Output Variables: All listed above
  2. Get Records Element: Get Related Records
    • Object: Dynamic (based on ChildObjectName)
    • Filter: {RelationshipFieldName} = {!ParentRecordId} AND {StatusFieldName} != {!NewStatus} {FilterCriteria}
    • Store In: RelatedRecords (collection variable)
  3. Decision Node: Check if Records Exist
    • Outcome 1: RelatedRecords is not empty → Update Records
    • Outcome 2: RelatedRecords is empty → No Records to Update
  4. Assignment Element: Prepare Records for Update
    • Loop through RelatedRecords
    • Set {StatusFieldName} = {!NewStatus} for each record
  5. Update Records Element: Update Related Records
    • Records: RelatedRecords
    • How Many: Multiple
    • Fields: Update status field
    • Fault Path: Set error and continue
  6. Assignment Element: Set Success Output
    • RecordsUpdated = COUNT(RelatedRecords)
    • IsSuccess = true
    • ErrorMessage = ''
  7. Assignment Element: Set Error Output
    • RecordsUpdated = 0
    • IsSuccess = false
    • ErrorMessage = 'Failed to update records: ' & {!$Flow.FaultMessage}
  8. End Element: End Subflow

Key Points:

Example 3: Reusable Email Notification

Use Case: Send standardized email notifications that can be reused across multiple Flows.

Subflow Name: Subflow_Send_Email_Notification

Input Variables:

Output Variables:

Subflow Structure:

  1. Start Element: Subflow
    • Input Variables: All listed above
    • Output Variables: All listed above
  2. Decision Node: Check if Using Template
    • Outcome 1: UseTemplate = true → Use Email Template Path
    • Outcome 2: UseTemplate = false → Use Custom Email Path
  3. Send Email Element (Template Path):
    • Email Template: {!TemplateId}
    • Recipients: {!ToEmailAddresses}
    • Related Record: {!RelatedRecordId}
    • Store In: EmailResult (single record variable)
    • Fault Path: Set error and continue
  4. Send Email Element (Custom Path):
    • To Addresses: {!ToEmailAddresses}
    • Subject: {!EmailSubject}
    • Body: {!EmailBody}
    • Store In: EmailResult (single record variable)
    • Fault Path: Set error and continue
  5. Decision Node: Check Success
    • Outcome 1: EmailResult.Id != null → Success Path
    • Outcome 2: Default → Error Path
  6. Assignment Element: Set Success Output
    • EmailSent = true
    • ErrorMessage = ''
  7. Assignment Element: Set Error Output
    • EmailSent = false
    • ErrorMessage = 'Failed to send email: ' & {!$Flow.FaultMessage}
  8. End Element: End Subflow

Key Points:

Example 4: Reusable Data Validation

Use Case: Validate data format and business rules that can be reused across multiple Flows.

Subflow Name: Subflow_Validate_Contact_Data

Input Variables:

Output Variables:

Subflow Structure:

  1. Start Element: Subflow
    • Input Variables: All listed above
    • Output Variables: All listed above
  2. Assignment Element: Initialize Outputs
    • IsValid = true
    • ValidationErrors = ''
    • EmailValid = true
    • PhoneValid = true
    • DateOfBirthValid = true
  3. Decision Node: Validate Email
    • Outcome 1: CONTAINS(Email, '@') AND CONTAINS(Email, '.') → Email Valid
    • Outcome 2: Default → Email Invalid
  4. Assignment Element: Set Email Invalid
    • EmailValid = false
    • IsValid = false
    • ValidationErrors = {!ValidationErrors} & 'Invalid email format; '
  5. Decision Node: Validate Phone (if provided)
    • Outcome 1: ISBLANK(Phone) OR LEN(Phone) >= 10 → Phone Valid
    • Outcome 2: Default → Phone Invalid
  6. Assignment Element: Set Phone Invalid
    • PhoneValid = false
    • IsValid = false
    • ValidationErrors = {!ValidationErrors} & 'Invalid phone format; '
  7. Decision Node: Validate Date of Birth (if provided)
    • Outcome 1: ISBLANK(DateOfBirth) OR DateOfBirth < TODAY() → Date Valid
    • Outcome 2: Default → Date Invalid
  8. Assignment Element: Set Date Invalid
    • DateOfBirthValid = false
    • IsValid = false
    • ValidationErrors = {!ValidationErrors} & 'Date of birth must be in the past; '
  9. End Element: End Subflow

Usage in Parent Flow:

Call Subflow: Validate Contact Data
  Input:
    Email = {!EmailInput}
    Phone = {!PhoneInput}
    DateOfBirth = {!DateOfBirthInput}
  Output:
    IsValid → ValidationPassed variable
    ValidationErrors → ErrorMessages variable

Decision: Check Validation
  If IsValid = true → Continue
  If IsValid = false → Show Error Screen

Key Points:

Example 5: Reusable Assignment Logic

Use Case: Assign records to users or queues based on configurable rules.

Subflow Name: Subflow_Assign_Record_By_Rules

Input Variables:

Output Variables:

Subflow Structure:

  1. Start Element: Subflow
    • Input Variables: All listed above
    • Output Variables: All listed above
  2. Get Records Element: Get Assignment Rules (from Custom Metadata)
    • Object: AssignmentRule__mdt (custom metadata)
    • Filter: RecordType__c = {!RecordType} AND Active__c = true
    • Store In: AssignmentRules (collection variable)
    • Sort: Priority__c ASC
  3. Loop Element: Evaluate Rules
    • Loop Through: AssignmentRules
    • Current Item: CurrentRule
  4. Decision Node: Check Rule Criteria
    • Outcome 1: Priority = CurrentRule.Priority__c AND Region = CurrentRule.Region__c → Match
    • Outcome 2: Priority = CurrentRule.Priority__c → Match (Region not required)
    • Outcome 3: Default → No Match, Continue Loop
  5. Assignment Element: Set Assignment
    • AssignedToId = CurrentRule.AssignedToId__c
    • AssignmentReason = 'Assigned by rule: ' & CurrentRule.Label
    • IsSuccess = true
    • Exit Loop
  6. Decision Node: Check if Assigned
    • Outcome 1: ISBLANK(AssignedToId) → Use Default Assignment
    • Outcome 2: NOT(ISBLANK(AssignedToId)) → Assignment Complete
  7. Assignment Element: Set Default Assignment
    • AssignedToId = DefaultQueueId (from custom setting)
    • AssignmentReason = 'Assigned to default queue'
    • IsSuccess = true
  8. End Element: End Subflow

Key Points:

Testing Considerations

Test Scenarios

  1. Input Validation:
    • Test with all required inputs
    • Test with optional inputs (null and provided)
    • Test with invalid inputs
    • Test with edge cases (empty strings, null values)
  2. Logic Execution:
    • Test all decision node paths
    • Test loop iterations
    • Test conditional logic
    • Test default value assignments
  3. Output Validation:
    • Verify output variables are set correctly
    • Verify success/failure flags
    • Verify error messages
    • Verify data transformations
  4. Integration:
    • Test Subflow called from different parent Flows
    • Test Subflow called from Apex (if applicable)
    • Test with different data scenarios
    • Test error propagation to parent

Best Practices