Salesforce Flow → Apex: When to Migrate, When to Stay
A field guide to deciding which Flows are worth rewriting as Apex, and a practical step-by-step process for the migration. Based on dozens of real-world conversions.
If you’ve been on Salesforce for any length of time, you’ve inherited at least one Flow that nobody understands anymore. It works (mostly), it’s running in production (definitely), and the only person who knew how it was built left two re-orgs ago. Every time someone needs to change it, they hold their breath.
We get asked the same question almost every week: “Should we rewrite this in Apex?”
The honest answer is: sometimes, but less often than you think. Here’s how to decide.
Why this question even exists
Flow is great. It’s how Salesforce wants admins to build automation, and for 80% of use cases it’s the right tool — declarative, fast to ship, easy for the next person to read.
But Flow also has well-known limitations:
- Complex branching becomes unmanageable past 4 or 5 decision nodes. You end up with a screen-spanning spaghetti diagram nobody can review.
- Bulk processing is fragile. Flows can hit governor limits in ways that are hard to predict, especially when triggered from triggers or other flows.
- Error handling is primitive. You can catch a fault and route to a screen, but tracing what failed in a scheduled flow at 2am requires Setup access and a lot of clicking.
- Version control is awkward. Flow XML is technically diffable, but reviewing a Flow change in a pull request is painful compared to reviewing Apex.
- Testing is shallow. You can write Apex tests for a flow, but testing the flow logic itself (rather than its side effects) is harder than testing Apex directly.
When you hit any of these walls, the question of migration starts to matter.
The decision matrix
We use a simple 5-question scorecard. For each Flow you’re considering migrating, give it a 0 or 1 on each question:
1. Has this Flow caused a production incident in the last 12 months? (0 = no, 1 = yes)
2. Does it have more than 5 decision nodes or 10 elements total? (0 = no, 1 = yes)
3. Is it triggered from a Record-Triggered Flow chain (i.e. it’s part of a multi-flow orchestration)? (0 = no, 1 = yes)
4. Does it process more than 200 records in a single execution under normal conditions? (0 = no, 1 = yes)
5. Has the original author left the team? (0 = no, 1 = yes)
Score interpretation:
- 0–1: Leave it alone. Flow is fine. Don’t migrate.
- 2–3: Refactor in place. Simplify the Flow before considering Apex.
- 4–5: Migrate to Apex. The cost of not migrating is higher than the cost of doing it right.
This isn’t a perfect heuristic, but it’s better than “we should rewrite everything in Apex” (we shouldn’t) or “Flow is always best” (it isn’t).
The migration process — 6 steps
Once you’ve decided a Flow is worth migrating, here’s the process we follow.
Step 1 — Document the current behavior
Before you write a line of Apex, document what the Flow actually does. Not what the Flow diagram suggests it does — what it actually does in production. The two are often different.
We do this by:
- Reading the Flow XML directly (Setup → Object Manager → Flow → Export)
- Running the Flow against a sandbox with debug logging on, capturing 5–10 representative scenarios
- Listing every record type, field, and side effect the Flow touches
If you skip this step, your Apex rewrite will faithfully reproduce a Flow that didn’t actually do what you thought it did. We’ve seen this end badly more than once.
Step 2 — Write the Apex tests first
Counterintuitive but critical. Before writing the Apex implementation, write the Apex tests that capture the documented behavior from Step 1. Each scenario becomes a test method.
The tests should fail (because the implementation doesn’t exist yet). That’s fine. Now you have a target.
This is the single most important practice in any migration. It means you can’t ship a regression without noticing it, because the tests would catch it.
Step 3 — Implement Apex with the same surface area
Build the Apex class to have the same trigger surface as the Flow. If the Flow runs on Account.afterUpdate, the Apex trigger does too. If the Flow uses a custom invocable action, the Apex method does too.
Don’t try to “improve” the design in this step. Migration is not refactoring. Get behavior parity first. Refactor later, in a separate, smaller change.
Step 4 — Run both in parallel for a week
Critical step. Don’t deactivate the Flow yet. Instead:
- Add a feature flag (custom metadata, custom setting, or hierarchy custom setting)
- When the flag is
false, the Flow runs and the Apex runs but logs to a Custom Object instead of writing - When the flag is
true, the Apex writes and the Flow is bypassed via an early-exit decision
For one week, run both side-by-side. Compare the Custom Object log entries against what the Flow actually did. Any divergence is a bug in your migration.
This step catches the 5% of behaviors you missed in Step 1. It is the difference between a smooth migration and a Friday afternoon “all sales reps’ opportunities just got the wrong stage” incident.
Step 5 — Cut over
When the parallel run is clean, flip the flag. Apex is now authoritative. Leave the Flow active but neutered (with the early-exit) for another two weeks as a safety net.
If anything looks wrong in production during those two weeks, you can flip the flag back and the Flow takes over again — zero downtime, zero panic.
Step 6 — Decommission
After two weeks of clean operation, deactivate the Flow, delete the early-exit logic from your Apex, and remove the feature flag. You’re done.
Document the migration in a wiki page or PR description so the next person knows what happened and why. The single biggest sin of any migration is leaving no record of why it was done.
The patterns that benefit most from migration
In our experience, these specific patterns are almost always worth moving from Flow to Apex:
1. Complex assignment logic
If your Flow has more than 3 nested decisions, route-to-team logic, or multi-criteria assignment, Apex is more readable and easier to maintain. Build a LeadAssignmentService class with clear methods, and it’ll be easier to evolve over five years than a 40-element Flow.
2. Bulk data processing
Flow’s bulk handling is fragile under load. If your automation regularly processes >200 records at a time, Apex with proper bulk patterns (Map-based aggregation, Database.update with allOrNone=false) is safer.
3. Orchestrations across multiple objects
If you have a Flow that spans 4+ objects with side effects on each, that’s an orchestration, and orchestrations belong in code where the control flow is explicit.
4. Anything with “we don’t dare touch it”
This is the most important category. If your team treats a Flow as a black box because nobody understands it, the real problem isn’t Flow vs Apex — it’s that you can’t reason about what’s running in your org. Migration is the forcing function that makes you understand it.
The patterns that should stay in Flow
Don’t migrate these. Flow is the right tool:
- Single-record automations — when X happens, do Y. One trigger, one action.
- Screen flows for users — Apex would be a worse tool, period.
- Approval routing — Flow’s visual approval process is hard to beat.
- Quick admin tasks — anything an admin needs to ship in an afternoon.
- Anything an admin will need to update — if the business rules will change quarterly, keep them where the admin can edit them without involving a developer.
Using Claude Code to accelerate the migration
The migration process above takes 1–3 days per Flow when done by a human. We’ve cut that to 4–8 hours per Flow using Claude Code as the implementation partner.
The pattern:
- Hand Claude Code the exported Flow XML and your behavior documentation from Step 1
- Ask for: “Generate Apex tests that capture this behavior, then generate the trigger and handler class to make those tests pass. Use bulk-safe patterns and our existing service-class conventions.”
- Review the diff. Iterate on edge cases.
- Run the tests in a scratch org. Iterate until they pass.
- Deploy to sandbox and follow the parallel-run process from Step 4.
Claude Code is genuinely good at this because Flow → Apex is a translation problem with clear input and output. Both sides are well-documented in its training data. Where Claude Code falls down is the behavioral documentation in Step 1 — that part is on you, because only you know what your org actually does.
For more on using Claude Code in Salesforce work, see our Claude Code for Salesforce admins guide.
The honest summary
Most Flows shouldn’t be migrated. The ones that should are the ones that hurt to maintain — the ones with the spaghetti diagrams, the production incidents, and the “we don’t dare touch it” stickers. For those, the migration is worth it, and the parallel-run process above means you can do it without risking production.
If you’re staring at a Flow and wondering whether it’s worth the rewrite, send us the export and we’ll tell you straight. We’ve done this enough times that we can usually answer the question in 15 minutes.
10 Automations Every Salesforce Admin Should Build in 2026
Build times, impact ratings, and the exact patterns we use for clients.
More in Salesforce
Claude Code for Salesforce Admins: A Practical Starter Guide
How Salesforce admins and developers can use Claude Code to ship Apex, LWC, and Flow work in hours instead of days — without replacing the discipline that keeps production orgs healthy.
How to Build AI Lead Scoring in Salesforce with Claude: A Complete Technical Guide
A step-by-step guide to building real AI lead scoring in Salesforce using Claude's API — including Named Credentials, Queueable Apex, Custom Metadata Types, a test class, cost estimates, and data security considerations. No Agentforce license required.
How Much Does a Salesforce Implementation Cost? (2026 Guide)
Honest price ranges for Salesforce Sales Cloud, Service Cloud, Experience Cloud, and enterprise implementations in 2026 — what drives cost and how to scope a project before talking to anyone.
Have a system you'd like us to build?
We turn repetitive work into automations that run in the background — so your team does the work that matters.
Multiply Your Output