Back to skills
SKILL.md
081 Parent Bca22915
ASecurityThe **Parent-Child pattern** is an orchestration approach where a parent flow coordinates multiple child subflows, each handling a specific responsibility. This creates modular, maintainable automation that's easier to test, debug, and enhance.
- 9 stars
- 0 votes
- 0 copies
- 0 views
- Added October 11, 2026
Works with
Security analysis
100/100npx -y skills add tools-only/X-Skills --skill 081-parent_bca22915 --agent claude-codeAre you the author of 081 Parent Bca22915?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/tools-only-081-parent-bca22915)# Orchestration Pattern: Parent-Child
## Overview
The **Parent-Child pattern** is an orchestration approach where a parent flow coordinates multiple child subflows, each handling a specific responsibility. This creates modular, maintainable automation that's easier to test, debug, and enhance.
## When to Use This Pattern
✅ **Use Parent-Child when:**
- Complex automation has multiple distinct steps
- Different teams own different parts of the logic
- You need to reuse steps across multiple parent flows
- Testing and debugging large flows is difficult
- Changes to one step shouldn't require retesting everything
❌ **Don't use when:**
- Automation is simple with 1-2 steps
- All logic is tightly coupled
- Performance is critical (minimal subflow overhead acceptable)
## Real-World Example: Account Industry Change
### Business Requirement
When an Account's Industry changes:
1. Update all related Contacts with the new Industry
2. Update all related Opportunities with Industry-specific Stage
3. Send notification to Account Owner
4. Log the change for audit purposes
### ❌ Monolithic Approach (Anti-Pattern)
One large flow with everything inline:
```
RTF_Account_IndustryChange
├── Get Related Contacts (150+ records)
├── Loop Through Contacts
│ └── Update Each Contact (DML in loop! ❌)
├── Get Related Opportunities
├── Decision: Industry = "Technology"?
│ ├── Yes → Update Stage to "Discovery"
│ └── No → Update Stage to "Qualification"
├── Loop Through Opportunities
│ └── Update Each Opportunity (DML in loop! ❌)
├── Send Email to Owner
└── Create Audit Log
Problems:
- 400+ lines of XML
- DML in loops causes bulk failures
- Can't reuse Contact update logic elsewhere
- Testing requires full end-to-end scenario
- Debugging is painful
```
### ✅ Parent-Child Approach (Best Practice)
Break into coordinated flows:
```
Parent: RTF_Account_IndustryChange_Orchestrator
├── Child: Sub_UpdateContactIndustry (reusable)
├── Child: Sub_UpdateOpportunityStages (reusable)
├── Child: Sub_SendEmailAlert (from library)
└── Child: Sub_CreateAuditLog (reusable)
Benefits:
- Each child is 50-100 lines
- Each child can be tested independently
- Children can be reused in other flows
- Clear separation of concerns
- Easy to add/remove steps
```
## Implementation
### Parent Flow: RTF_Account_IndustryChange_Orchestrator
```xml
<?xml version="1.0" encoding="UTF-8"?>
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>65.0</apiVersion>
<description>Parent orchestrator that coordinates industry change automation. Calls child subflows for each responsibility.</description>
<label>RTF_Account_IndustryChange_Orchestrator</label>
<processMetadataValues>
<name>BuilderType</name>
<value>
<stringValue>LightningFlowBuilder</stringValue>
</value>
</processMetadataValues>
<processType>AutoLaunchedFlow</processType>
<start>
<locationX>0</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Update_Contacts</targetReference>
</connector>
<object>Account</object>
<recordTriggerType>Update</recordTriggerType>
<triggerType>RecordAfterSave</triggerType>
</start>
<status>Draft</status>
<!-- Step 1: Update Related Contacts -->
<subflows>
<name>Update_Contacts</name>
<label>Update Related Contacts</label>
<locationX>0</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Update_Opportunities</targetReference>
</connector>
<flowName>Sub_UpdateContactIndustry</flowName>
<inputAssignments>
<name>varAccountId</name>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<name>varNewIndustry</name>
<value>
<elementReference>$Record.Industry</elementReference>
</value>
</inputAssignments>
</subflows>
<!-- Step 2: Update Related Opportunities -->
<subflows>
<name>Update_Opportunities</name>
<label>Update Related Opportunities</label>
<locationX>0</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Notify_Owner</targetReference>
</connector>
<flowName>Sub_UpdateOpportunityStages</flowName>
<inputAssignments>
<name>varAccountId</name>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<name>varIndustry</name>
<value>
<elementReference>$Record.Industry</elementReference>
</value>
</inputAssignments>
</subflows>
<!-- Step 3: Send Notification -->
<subflows>
<name>Notify_Owner</name>
<label>Notify Account Owner</label>
<locationX>0</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Create_Audit_Log</targetReference>
</connector>
<flowName>Sub_SendEmailAlert</flowName>
<inputAssignments>
<name>varEmailAddresses</name>
<value>
<elementReference>$Record.Owner.Email</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<name>varEmailSubject</name>
<value>
<stringValue>Account Industry Updated</stringValue>
</value>
</inputAssignments>
<inputAssignments>
<name>varEmailBody</name>
<value>
<stringValue>Account {!$Record.Name} industry changed to {!$Record.Industry}. Related records have been updated.</stringValue>
</value>
</inputAssignments>
</subflows>
<!-- Step 4: Audit Logging -->
<subflows>
<name>Create_Audit_Log</name>
<label>Create Audit Log</label>
<locationX>0</locationX>
<locationY>0</locationY>
<flowName>Sub_CreateAuditLog</flowName>
<inputAssignments>
<name>varObjectName</name>
<value>
<stringValue>Account</stringValue>
</value>
</inputAssignments>
<inputAssignments>
<name>varRecordId</name>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<name>varFieldChanged</name>
<value>
<stringValue>Industry</stringValue>
</value>
</inputAssignments>
<inputAssignments>
<name>varNewValue</name>
<value>
<elementReference>$Record.Industry</elementReference>
</value>
</inputAssignments>
</subflows>
</Flow>
```
### Child Flow 1: Sub_UpdateContactIndustry
```xml
<?xml version="1.0" encoding="UTF-8"?>
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>65.0</apiVersion>
<description>Updates Industry field on all Contacts related to an Account. Bulkified and reusable.</description>
<label>Sub_UpdateContactIndustry</label>
<processType>AutoLaunchedFlow</processType>
<!-- Get Related Contacts -->
<recordLookups>
<name>Get_Related_Contacts</name>
<label>Get Related Contacts</label>
<locationX>0</locationX>
<locationY>0</locationY>
<assignNullValuesIfNoRecordsFound>false</assignNullValuesIfNoRecordsFound>
<connector>
<targetReference>Check_If_Contacts_Found</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>AccountId</field>
<operator>EqualTo</operator>
<value>
<elementReference>varAccountId</elementReference>
</value>
</filters>
<getFirstRecordOnly>false</getFirstRecordOnly>
<object>Contact</object>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordLookups>
<!-- Decision: Were contacts found? -->
<decisions>
<name>Check_If_Contacts_Found</name>
<label>Contacts Found?</label>
<locationX>0</locationX>
<locationY>0</locationY>
<defaultConnectorLabel>No Contacts</defaultConnectorLabel>
<rules>
<name>Contacts_Exist</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>Get_Related_Contacts</leftValueReference>
<operator>IsNull</operator>
<rightValue>
<booleanValue>false</booleanValue>
</rightValue>
</conditions>
<connector>
<targetReference>Update_Contacts_Bulk</targetReference>
</connector>
<label>Contacts Exist</label>
</rules>
</decisions>
<!-- Bulk Update (NO DML in loops!) -->
<recordUpdates>
<name>Update_Contacts_Bulk</name>
<label>Update Contacts (Bulk)</label>
<locationX>0</locationX>
<locationY>0</locationY>
<faultConnector>
<targetReference>Log_Update_Error</targetReference>
</faultConnector>
<inputAssignments>
<field>Industry</field>
<value>
<elementReference>varNewIndustry</elementReference>
</value>
</inputAssignments>
<inputReference>Get_Related_Contacts</inputReference>
</recordUpdates>
<!-- Error Handler -->
<subflows>
<name>Log_Update_Error</name>
<label>Log Update Error</label>
<locationX>0</locationX>
<locationY>0</locationY>
<flowName>Sub_LogError</flowName>
<inputAssignments>
<name>varErrorMessage</name>
<value>
<elementReference>$Flow.FaultMessage</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<name>varFlowName</name>
<value>
<stringValue>Sub_UpdateContactIndustry</stringValue>
</value>
</inputAssignments>
<inputAssignments>
<name>varRecordId</name>
<value>
<elementReference>varAccountId</elementReference>
</value>
</inputAssignments>
</subflows>
<start>
<locationX>0</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Get_Related_Contacts</targetReference>
</connector>
</start>
<status>Draft</status>
<!-- Input Variables -->
<variables>
<name>varAccountId</name>
<dataType>String</dataType>
<isInput>true</isInput>
<isOutput>false</isOutput>
</variables>
<variables>
<name>varNewIndustry</name>
<dataType>String</dataType>
<isInput>true</isInput>
<isOutput>false</isOutput>
</variables>
</Flow>
```
### Child Flow 2: Sub_UpdateOpportunityStages
```xml
<?xml version="1.0" encoding="UTF-8"?>
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>65.0</apiVersion>
<description>Updates Opportunity Stages based on Industry. Demonstrates conditional logic in child flows.</description>
<label>Sub_UpdateOpportunityStages</label>
<processType>AutoLaunchedFlow</processType>
<!-- Get Related Opportunities -->
<recordLookups>
<name>Get_Related_Opportunities</name>
<label>Get Related Opportunities</label>
<locationX>0</locationX>
<locationY>0</locationY>
<assignNullValuesIfNoRecordsFound>false</assignNullValuesIfNoRecordsFound>
<connector>
<targetReference>Check_If_Opportunities_Found</targetReference>
</connector>
<filterLogic>and</filterLogic>
<filters>
<field>AccountId</field>
<operator>EqualTo</operator>
<value>
<elementReference>varAccountId</elementReference>
</value>
</filters>
<filters>
<field>IsClosed</field>
<operator>EqualTo</operator>
<value>
<booleanValue>false</booleanValue>
</value>
</filters>
<getFirstRecordOnly>false</getFirstRecordOnly>
<object>Opportunity</object>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordLookups>
<!-- Decision: Were opportunities found? -->
<decisions>
<name>Check_If_Opportunities_Found</name>
<label>Opportunities Found?</label>
<locationX>0</locationX>
<locationY>0</locationY>
<defaultConnectorLabel>No Opportunities</defaultConnectorLabel>
<rules>
<name>Opportunities_Exist</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>Get_Related_Opportunities</leftValueReference>
<operator>IsNull</operator>
<rightValue>
<booleanValue>false</booleanValue>
</rightValue>
</conditions>
<connector>
<targetReference>Determine_Stage_By_Industry</targetReference>
</connector>
<label>Opportunities Exist</label>
</rules>
</decisions>
<!-- Decision: Which stage based on Industry? -->
<decisions>
<name>Determine_Stage_By_Industry</name>
<label>Determine Stage By Industry</label>
<locationX>0</locationX>
<locationY>0</locationY>
<defaultConnector>
<targetReference>Set_Default_Stage</targetReference>
</defaultConnector>
<defaultConnectorLabel>Other Industries</defaultConnectorLabel>
<rules>
<name>Technology_Industry</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>varIndustry</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>Technology</stringValue>
</rightValue>
</conditions>
<connector>
<targetReference>Set_Technology_Stage</targetReference>
</connector>
<label>Technology</label>
</rules>
<rules>
<name>Healthcare_Industry</name>
<conditionLogic>and</conditionLogic>
<conditions>
<leftValueReference>varIndustry</leftValueReference>
<operator>EqualTo</operator>
<rightValue>
<stringValue>Healthcare</stringValue>
</rightValue>
</conditions>
<connector>
<targetReference>Set_Healthcare_Stage</targetReference>
</connector>
<label>Healthcare</label>
</rules>
</decisions>
<!-- Assignment: Technology Stage -->
<assignments>
<name>Set_Technology_Stage</name>
<label>Set Technology Stage</label>
<locationX>0</locationX>
<locationY>0</locationY>
<assignmentItems>
<assignToReference>varNewStage</assignToReference>
<operator>Assign</operator>
<value>
<stringValue>Discovery</stringValue>
</value>
</assignmentItems>
<connector>
<targetReference>Update_Opportunity_Stages</targetReference>
</connector>
</assignments>
<!-- Assignment: Healthcare Stage -->
<assignments>
<name>Set_Healthcare_Stage</name>
<label>Set Healthcare Stage</label>
<locationX>0</locationX>
<locationY>0</locationY>
<assignmentItems>
<assignToReference>varNewStage</assignToReference>
<operator>Assign</operator>
<value>
<stringValue>Needs Analysis</stringValue>
</value>
</assignmentItems>
<connector>
<targetReference>Update_Opportunity_Stages</targetReference>
</connector>
</assignments>
<!-- Assignment: Default Stage -->
<assignments>
<name>Set_Default_Stage</name>
<label>Set Default Stage</label>
<locationX>0</locationX>
<locationY>0</locationY>
<assignmentItems>
<assignToReference>varNewStage</assignToReference>
<operator>Assign</operator>
<value>
<stringValue>Qualification</stringValue>
</value>
</assignmentItems>
<connector>
<targetReference>Update_Opportunity_Stages</targetReference>
</connector>
</assignments>
<!-- Bulk Update Opportunities -->
<recordUpdates>
<name>Update_Opportunity_Stages</name>
<label>Update Opportunity Stages</label>
<locationX>0</locationX>
<locationY>0</locationY>
<faultConnector>
<targetReference>Log_Update_Error</targetReference>
</faultConnector>
<inputAssignments>
<field>StageName</field>
<value>
<elementReference>varNewStage</elementReference>
</value>
</inputAssignments>
<inputReference>Get_Related_Opportunities</inputReference>
</recordUpdates>
<!-- Error Handler -->
<subflows>
<name>Log_Update_Error</name>
<label>Log Update Error</label>
<locationX>0</locationX>
<locationY>0</locationY>
<flowName>Sub_LogError</flowName>
<inputAssignments>
<name>varErrorMessage</name>
<value>
<elementReference>$Flow.FaultMessage</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<name>varFlowName</name>
<value>
<stringValue>Sub_UpdateOpportunityStages</stringValue>
</value>
</inputAssignments>
<inputAssignments>
<name>varRecordId</name>
<value>
<elementReference>varAccountId</elementReference>
</value>
</inputAssignments>
</subflows>
<start>
<locationX>0</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Get_Related_Opportunities</targetReference>
</connector>
</start>
<status>Draft</status>
<!-- Variables -->
<variables>
<name>varAccountId</name>
<dataType>String</dataType>
<isInput>true</isInput>
<isOutput>false</isOutput>
</variables>
<variables>
<name>varIndustry</name>
<dataType>String</dataType>
<isInput>true</isInput>
<isOutput>false</isOutput>
</variables>
<variables>
<name>varNewStage</name>
<dataType>String</dataType>
<isInput>false</isInput>
<isOutput>false</isOutput>
</variables>
</Flow>
```
## Benefits of This Pattern
### 1. **Modularity**
Each child flow has one clear responsibility:
- Sub_UpdateContactIndustry: Only handles Contact updates
- Sub_UpdateOpportunityStages: Only handles Opportunity logic
- Sub_SendEmailAlert: Only handles notifications
### 2. **Reusability**
Child flows can be called from multiple parents:
```
RTF_Account_IndustryChange → Sub_UpdateContactIndustry
RTF_Account_Merge → Sub_UpdateContactIndustry
Auto_BulkIndustryUpdate → Sub_UpdateContactIndustry
```
### 3. **Testability**
Test each child independently:
- Unit test: Sub_UpdateContactIndustry with 200 Contacts
- Unit test: Sub_UpdateOpportunityStages with various Industries
- Integration test: Parent flow with full scenario
### 4. **Maintainability**
Update logic in one place:
- Need to change Contact update logic? Edit Sub_UpdateContactIndustry
- All parent flows automatically get the update
- No need to find/replace across multiple flows
### 5. **Debugging**
Clear error isolation:
- Error in Contact update? Check Sub_UpdateContactIndustry logs
- Parent flow shows which step failed
- Error logs show exact subflow name
## Performance Considerations
### Governor Limits
- **Subflow Depth**: Max 50 levels (parent → child → grandchild...)
- **DML Statements**: Each child's DML counts toward 150 limit
- **SOQL Queries**: Each child's query counts toward 100 limit
### Best Practices
✅ Keep parent flow lightweight (orchestration only)
✅ Put complex logic in children
✅ Use bulkified operations in each child
✅ Monitor total DML/SOQL across all children
## Testing Strategy
### 1. Unit Test Each Child
```bash
# Test Sub_UpdateContactIndustry
Create 200 test Contacts → Manually invoke flow → Verify all updated
```
### 2. Integration Test Parent
```bash
# Test full orchestration
Update Account Industry → Verify all children executed → Check audit logs
```
### 3. Bulk Test
```bash
# Test with 200+ Accounts
Data Loader update 200 Accounts → Verify no governor limit errors
```
## When to Add More Children
Add a new child subflow when:
- New requirement emerges (e.g., "Also update Cases")
- Existing child gets too complex (>200 lines)
- You need to reuse logic elsewhere
```xml
<!-- Adding a new step is easy -->
<subflows>
<name>Update_Cases</name>
<label>Update Related Cases</label>
<locationX>0</locationX>
<locationY>0</locationY>
<connector>
<targetReference>Notify_Owner</targetReference>
</connector>
<flowName>Sub_UpdateCaseIndustry</flowName>
<inputAssignments>
<name>varAccountId</name>
<value>
<elementReference>$Record.Id</elementReference>
</value>
</inputAssignments>
<inputAssignments>
<name>varIndustry</name>
<value>
<elementReference>$Record.Industry</elementReference>
</value>
</inputAssignments>
</subflows>
```
## Related Patterns
- [Sequential Orchestration](orchestration-sequential.md) - Chain flows A → B → C
- [Conditional Orchestration](orchestration-conditional.md) - Parent decides which children to call
- [Subflow Library](../docs/subflow-library.md) - Reusable subflow templates
## Summary
**Parent-Child orchestration** transforms complex automations from monolithic nightmares into modular, maintainable architectures. Each child flow is focused, testable, and reusable—making your entire automation ecosystem more robust.
**Key Takeaway**: If your flow has more than 3 distinct responsibilities, consider breaking it into a parent orchestrator with child subflows. Your future self (and your team) will thank you! 🚀
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.