flow-migration-from-trigger
Decide whether an existing Apex trigger should be rewritten as a Flow, and execute the migration safely. Covers the decision criteria (complexity, ownership, performance), side-by-side rollout, test-coverage parity, and the inverse case (recognize when Flow should stay Apex). NOT for migrating Process Builder / Workflow Rule to Flow (use those migration skills). NOT for brand-new automation decisions (use automation-selection.md).
Best use case
flow-migration-from-trigger is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Decide whether an existing Apex trigger should be rewritten as a Flow, and execute the migration safely. Covers the decision criteria (complexity, ownership, performance), side-by-side rollout, test-coverage parity, and the inverse case (recognize when Flow should stay Apex). NOT for migrating Process Builder / Workflow Rule to Flow (use those migration skills). NOT for brand-new automation decisions (use automation-selection.md).
Teams using flow-migration-from-trigger should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/flow-migration-from-trigger/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How flow-migration-from-trigger Compares
| Feature / Agent | flow-migration-from-trigger | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Decide whether an existing Apex trigger should be rewritten as a Flow, and execute the migration safely. Covers the decision criteria (complexity, ownership, performance), side-by-side rollout, test-coverage parity, and the inverse case (recognize when Flow should stay Apex). NOT for migrating Process Builder / Workflow Rule to Flow (use those migration skills). NOT for brand-new automation decisions (use automation-selection.md).
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Flow Migration from Trigger
## Core concept — not every trigger should migrate
Apex triggers earn their complexity. Migration is justified when Flow can credibly carry the load AND admin ownership is desirable. Migration is harmful when:
- The trigger orchestrates complex transaction control (SavePoints, multi-SOQL joins, recursion control) that Flow doesn't express cleanly.
- The trigger issues callouts, which are constrained in Flow's After-Save context.
- The trigger runs in high-volume contexts where the per-element overhead of Flow (vs tight Apex) matters.
## Migration decision matrix
| Trigger characteristic | Migrate to Flow? |
|---|---|
| Single-object field derivation | ✅ Yes — use Before-Save record-triggered flow |
| Create related records on save | ✅ Yes — After-Save record-triggered flow |
| Cross-object updates with moderate logic | ✅ Yes — After-Save record-triggered flow |
| Bulk processing (1000+ records per transaction) | ⚠️ Maybe — benchmark before migrating |
| Callouts or async work | ⚠️ Route via Scheduled Path or Platform Event |
| SavePoint / complex transaction control | ❌ No — keep Apex |
| Recursion control via static context | ❌ No — keep Apex |
| Integration with @future / Queueable | ❌ No — keep Apex |
| Custom exception wrapping / logging frameworks | ❌ No — keep Apex |
| SOQL-heavy joins and aggregations | ❌ No — keep Apex |
## Recommended Workflow
1. **Read the trigger + handler** end-to-end. Note all DML, SOQL, and decision branches.
2. **Classify each branch** against the decision matrix. If any branch is "No", consider keeping Apex OR splitting the trigger (keep complex branches in Apex, migrate simple branches to Flow).
3. **Inventory tests.** Every test case that exercises the trigger must still pass after migration. If coverage is weak, shore it up BEFORE migration, not after.
4. **Design the Flow.** Match the trigger's timing (Before-Save vs After-Save), bulk context, and field updates.
5. **Plan side-by-side rollout.** Deploy the Flow inactive; activate in sandbox; run existing tests; smoke-test against a business-representative data set; activate in prod behind a Custom Permission for a subset of users.
6. **Deactivate the trigger.** Don't delete until 2+ release cycles confirm the Flow is stable. Keep the trigger source code for rollback.
7. **Declare migration complete** only when: tests green, zero runtime errors for 30 days, admin team confirms ownership.
## Key patterns
### Pattern 1 — Simple field-derivation migration
Original trigger handler:
```apex
for (Account acc : Trigger.new) {
if (acc.Billing_Country__c == 'United States') {
acc.Region__c = 'NA';
} else if (acc.Billing_Country__c == 'Germany') {
acc.Region__c = 'EMEA';
}
}
```
Flow equivalent (Before-Save record-triggered):
```
[Decision: Billing_Country__c]
├── "United States" → [Assignment: $Record.Region__c = 'NA']
├── "Germany" → [Assignment: $Record.Region__c = 'EMEA']
└── default → [Assignment: $Record.Region__c = 'ROW']
```
Benefits post-migration:
- Admin can add new country → region mappings without code.
- Before-Save avoids DML cost (free field update).
- Same transaction semantics as the original trigger.
### Pattern 2 — Partial migration
Handler with two responsibilities:
- Simple branch: set `Region__c` from country (migrate).
- Complex branch: SOQL-join parent account's preferences + SavePoint + external callout (keep in Apex).
Split:
- Flow handles region.
- Trigger now only runs the complex branch.
- Both coexist; each fires on the same save.
The test suite must verify both fire in the correct order (Before-Save Flow fires first, then Apex After-Insert/Update trigger).
### Pattern 3 — Side-by-side rollout with Custom Permission
```
Trigger handler:
if (!FeatureManagement.checkPermission('New_Flow_Active')) {
// run the old logic
} else {
// skip; flow will handle
}
```
Admins grant `New_Flow_Active` Custom Permission to a PSG; ramps from 1 user → 10% → 100%. If regression, revoke PSG; old logic resumes.
### Pattern 4 — Bulk benchmark before migration
Bulk-heavy trigger (1000+ records per batch): before migrating, measure per-record time in Apex vs expected Flow runtime. Flows process per record with element overhead; complex Flow logic at scale can exceed Apex by 2-5× in CPU time.
Measurement:
- Log Apex handler CPU time on a 200-record batch.
- In sandbox, run the equivalent Flow on the same 200-record fixture.
- If Flow is > 30% slower and the savings from Apex are material to user experience, KEEP Apex.
## Bulk safety
- Flow migration must preserve bulk semantics. A trigger handler that queries once and caches results must be replicated as Flow with Get Records outside loops.
- Order-of-execution changes: Before-Save Flow fires before Before-triggers in Apex. Verify no dependency inversion (e.g., Apex Before-trigger sets a value the Flow then reads).
## Error handling
- Every Flow branch needs a fault connector; triggers bubble Apex exceptions by default. Migration must preserve the error-surfacing behavior.
- Log to Integration_Log__c (see `skills/flow/flow-error-monitoring`) instead of relying on fault emails.
## Well-Architected mapping
- **Reliability** — a successful migration preserves behavior. A rushed migration introduces silent regressions. Side-by-side rollout + test parity is the safeguard.
- **Operational Excellence** — admin-maintainable automation is a real productivity gain at portfolio scale, but only if the migration doesn't cost more in fragile transitions than it saves in ongoing maintenance.
- **Performance** — Flow has per-element overhead; don't migrate hot-path triggers without benchmarking.
## Gotchas
See `references/gotchas.md`.
## Testing
The migration test strategy is **parity testing**:
1. Run the existing trigger test suite against the pre-migration org state; record outcomes.
2. Deactivate trigger, activate Flow.
3. Re-run the same test suite; every test must produce identical outcomes.
4. If any test fails, the migration introduced a regression — don't proceed.
Add NEW test cases that specifically exercise Flow-only concerns (fault paths, Before-Save semantics).
## Official Sources Used
- Salesforce Help — Decide Between Flow and Apex: https://help.salesforce.com/s/articleView?id=sf.flow_concepts_trigger.htm
- Salesforce Developer — Trigger Order of Execution: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_order_of_execution.htm
- Salesforce Architects — Automation Modernization Patterns: https://architect.salesforce.com/
- Salesforce Help — Flow Trigger Types: https://help.salesforce.com/s/articleView?id=sf.flow_ref_triggers.htmRelated Skills
ip-range-and-login-flow-strategy
Design and implement Salesforce Login Flows (Screen Flows assigned to profiles or Experience Cloud sites) that run post-authentication to enforce conditional MFA, IP-based branching, terms-of-service acceptance, or user data collection. Covers Login Flow creation in Flow Builder, profile/site assignment, IP-aware decision logic, and ConnectedAppPlugin extension points. NOT for static IP allowlisting or profile Login IP Ranges (see network-security-and-trusted-ips), org-wide session policies, or SSO/SAML IdP configuration.
customer-data-request-workflow
Implement GDPR/CCPA data subject rights (access, deletion, rectification) using Salesforce Privacy Center and/or custom workflow. NOT for general backup or org-level data retention policy.
vlocity-to-native-omnistudio-migration
Use when migrating an org from the Vlocity managed package (vlocity_ins, vlocity_cmt, vlocity_ps) to native OmniStudio. Trigger keywords: Vlocity to OmniStudio migration, namespace migration, vlocity_ins to omnistudio, OmniStudio Migration Tool, DataRaptor namespace update, OmniScript JSON export, managed package to native. NOT for new OmniStudio setup in greenfield orgs, nor for migrating between OmniStudio-native orgs, nor for Salesforce CPQ to Industries CPQ migration.
omnistudio-vs-flow-decision
Use when choosing between OmniStudio (OmniScript / Integration Procedure / FlexCard / DataRaptor) and Flow / Screen Flow / Apex for a given capability. Triggers: 'omnistudio or flow', 'omniscript vs screen flow', 'integration procedure vs subflow', 'flexcard vs lightning page'. NOT for general automation selection across Workflow/Process Builder/Apex (see automation-selection tree).
omnistudio-lwc-omniscript-migration
Migrate classic Visualforce-based OmniScripts to LWC-based runtime with feature parity and regression testing. NOT for new OmniScript design.
visualforce-to-lwc-migration
Migrating Visualforce pages and components to Lightning Web Components: controller-to-Apex-method translation, viewstate replacement, custom URL parameter handling, PageReference-to-NavigationMixin mapping, Lightning Out coexistence, and inline VF retention strategy. NOT for new LWC development from scratch (use lwc-fundamentals) or Aura-to-LWC migration (use aura-to-lwc-migration).
lwc-locker-to-lws-migration
Migrating LWCs from Lightning Locker Service to Lightning Web Security (LWS) — flipping the org switch safely, identifying components likely to break, removing Locker workarounds that are now insecure, and validating third-party libraries that previously failed under SecureWindow/SecureElement proxies. NOT for Aura → LWC migration — see lwc/aura-to-lwc-migration. NOT for general LWC security review (XSS, public-API hardening) — see lwc/lwc-security and lwc/lwc-public-api-hardening.
lwc-in-flow-screens
Use when building, reviewing, or troubleshooting a custom Lightning Web Component that runs inside a Flow screen element, covering @api props exposed to Flow, FlowAttributeChangeEvent for output, validate() for user input validation, and flow navigation events. Triggers: 'lwc in flow screen', 'FlowAttributeChangeEvent', 'flow screen component not updating', 'flow validate method', 'flow navigation from lwc'. NOT for custom property editors (use custom-property-editor-for-flow), NOT for embedding a flow inside an LWC (use flow/screen-flows), NOT for auto-launched flows.
custom-property-editor-for-flow
Use when building or reviewing an LWC Custom Property Editor for Flow screen or action configuration, including the `configurationEditor` metadata hook, builder-side APIs, validation, and value-change events. Triggers: 'custom property editor', 'Flow configuration editor', 'builderContext', 'inputVariables', 'configurationEditor'. NOT for ordinary runtime screen-component behavior when no Flow Builder design-time customization is involved.
aura-to-lwc-migration
Migrating Aura components to LWC: feature mapping, interoperability wrappers, event translation, navigation patterns, and Aura-LWC coexistence strategies. NOT for new LWC development from scratch or Aura feature development.
slack-workflow-builder
Use this skill when designing or troubleshooting Slack Workflow Builder workflows that call Salesforce — especially the Salesforce connector step Run a Flow, mapping inputs/outputs, handling failures, and understanding limits. Triggers on: Slack Workflow Builder Salesforce, Run a Flow from Slack, autolaunched flow from Slack, Slack automation calling Salesforce. NOT for Salesforce Flow Builder tutorials unrelated to Slack (use flow skills), not for Flow Core Actions that send Slack messages from Salesforce (use flow-for-slack), not for initial org-to-workspace connection (use slack-salesforce-integration-setup), and not for building custom Slack apps outside Workflow Builder.
oauth-flows-and-connected-apps
Use when choosing or reviewing Salesforce OAuth flows and connected-app policy for integrations, including client credentials, JWT bearer, authorization code, device flow, scopes, and token lifecycle controls. Triggers: 'OAuth flow', 'connected app', 'client credentials', 'JWT bearer', 'refresh token', 'integration user'. NOT for record-level sharing design or for simple Named Credential usage when the auth-flow decision is already settled.