Build automation in Flow when the logic is mostly field updates, record creation, guided screens or scheduled sweeps. It fits best when admins will make later changes. Write Apex when the work needs tight transaction control, heavy data volumes, complex branching, reusable services or rigorous unit tests. Most healthy orgs use both: Flow for the visible process, invocable Apex for the hard parts, and one agreed pattern per object so the two never compete.
What can each kind of flow actually do?
Flow is not one tool but several flow types, each suited to a different trigger. Knowing which type you need settles half the Flow-or-Apex question before it starts.
- Before-save record-triggered flows (Fast Field Updates) change fields on the record being saved, before it reaches the database. Salesforce documents these as much faster than after-save logic, because the record is not saved a second time.
- After-save record-triggered flows (Actions and Related Records) run once the record is committed. Use them to create or update other records, send emails, post notifications or call subflows. They can also hold scheduled and asynchronous paths.
- Screen flows put a guided form in front of a user, from a button, a Lightning page or an Experience Cloud site. They suit intake steps, wizards and checklists where a person makes choices.
- Schedule-triggered flows wake up at a set time and frequency and act on a filtered batch of records, such as flagging stale opportunities each night.
- Autolaunched flows have no trigger of their own. Other flows, Apex, REST calls or platform events start them, which makes them the natural home for shared logic.
A good default for field defaults and derived values on the same record is a before-save flow. Reach for after-save only when the change touches something other than the triggering record.
Where does Flow Orchestration fit?
Orchestration coordinates a long-running process across several people and several flows, in stages and steps. It is for multi-day work like onboarding or approvals, not for single-transaction logic.
An orchestration groups steps into stages. Interactive steps assign a screen flow to a user, group or queue as a work item. Background steps run autolaunched flows without anyone clicking. Salesforce announced in early 2026 that Orchestration became a standard flow type, no longer a paid add-on, in Enterprise, Performance, Unlimited and Developer editions. Edition and entitlement details shift between releases, so confirm what your contract includes with your Salesforce account team.
Where does Flow start to struggle?
Flow struggles once logic gets deep, data gets large or failures must be handled precisely. None of these is a hard wall, but each raises the cost of keeping a flow correct.
- Complex logic. Nested decisions, collection juggling and many loops are hard to read on a canvas. A reviewer cannot diff two versions of a large flow as easily as two versions of a class.
- Data volume and limits. The runtime bulkifies record-triggered flows. Even so, a Get Records or Update Records element inside a loop spends queries and DML on every pass. Flow shares the same governor limits as any Apex running in that transaction.
- Error handling. Fault paths exist, yet many flows ship without them. Users then see a generic unhandled fault message and admins receive an email that rarely says which record failed or why.
- Testing. Flow tests are useful but narrower than Apex unit tests, as covered below.
- Version sprawl. Every save creates a version, and old inactive versions pile up. Several flows on one object, each added by a different admin over time, become hard to reason about as a set.
When is Apex clearly the better choice?
Choose Apex when correctness, scale or reuse matters more than who can edit the logic. In these cases code is cheaper to own than a flow that works around its own limits.
- Complex transactions. Apex can set savepoints and roll back part of the work, then decide what to commit. Multi-object updates with strict all-or-nothing rules are easier to guarantee in code.
- Integration patterns. Flow can call external systems through External Services and HTTP callout actions. Apex is still the better home for retry logic, authentication handling, response parsing and queueable chains that respect callout rules.
- High volume. Batch Apex and queueable jobs process large record sets in controlled chunks, with explicit limits checks along the way.
- Reusable services. A pricing calculation or eligibility check used by several flows, a Lightning component and an API endpoint belongs in one tested class, not five copies.
- Logic that must be proven. Apex tests can assert exact outcomes for single records, bulk loads, negative cases and different user permissions.
How do Flow and Apex work together in one org?
The most durable pattern is a flow that owns the process and calls Apex for the heavy steps. Admins keep control of the sequence, and developers keep control of the logic that needs code.
An Apex method marked @InvocableMethod appears in Flow Builder as an action with typed inputs and outputs. Because invocable methods receive a list, a well-written one handles 200 records in one call rather than 200 calls. The reverse also works: Apex can start an autolaunched flow, so a trigger handler can hand simple, admin-maintained steps back to Flow.
Abstrakt's work for a broker-dealer shows Flow carrying real weight in a custom build. Its capital-raising system on Salesforce used record-triggered and loop-based flows to create engagements and generate commission-split records, alongside custom objects and validation rules.
How should you govern automation across an org?
Agree one automation strategy per object and write it down. Most automation incidents come from two mechanisms acting on the same record without knowing about each other.
- Pick the owner per object. For each busy object, decide whether Apex triggers or record-triggered flows lead, and how the other one is allowed to join in.
- Use a trigger framework. One trigger per object that delegates to handler classes gives you predictable order, a single place to bypass logic during data loads and cleaner tests.
- Set flow trigger order. Flow Trigger Explorer lists the record-triggered flows for each object, along with their run sequence. Set explicit order values rather than relying on defaults.
- Name things consistently. A pattern such as Object_Timing_Purpose, for example Opportunity_BeforeSave_SetDefaults, tells a newcomer what a flow does before opening it.
- Document as you build. Fill in every flow description, list each element's purpose and record why logic sits in Flow or Apex. Clean out inactive versions on a regular schedule.
How is testing different for flows and Apex?
Apex has a hard deployment gate; Flow testing is mostly a discipline you choose. That difference alone pushes high-risk logic toward code in many orgs.
For Apex, Salesforce requires at least 75% of your code covered by unit tests before deploying to production. All tests must pass, and every trigger needs some coverage. Salesforce encourages aiming higher and covering positive, negative and bulk cases rather than chasing the percentage.
Flow tests can be built in Flow Builder for record-triggered, autolaunched and Data Cloud-triggered flows. Each test sets up a triggering record and asserts the expected outcome. There are gaps: flow tests do not support flows that run on delete or paths that run asynchronously. Autolaunched flows with callouts or Wait elements cannot be tested this way, and each flow allows at most 200 tests. Salesforce also notes that these tests do not count toward flow test-coverage requirements, so complex flows are often tested through Apex as well.
Who will maintain it, and why does that decide so much?
Match the tool to the team that will own the org in two years. A brilliant Apex service nobody on staff can read is a liability, and so is a sprawling flow nobody dares edit.
An org run by admins with occasional partner help should lean on Flow, keep Apex small and wrap it in invocable actions with clear names. An org with a standing development team can put more logic in code, provided changes go through source control, review and automated tests. Mixed teams do best with the hybrid pattern above and a short written agreement on who changes what.
Which tool fits which automation need?
Use this table as a starting point, then adjust for volume, ownership and how often the rule will change.
| Need | Lean toward | Why |
|---|---|---|
| Set defaults or derived fields on the saved record | Before-save flow | Fast, no extra save, easy for admins to adjust |
| Create related records or send alerts after save | After-save flow | Readable sequence; fine at normal volumes |
| Guided data entry or a multi-step form | Screen flow | Built for user interaction without custom UI |
| Nightly sweep of a modest record set | Schedule-triggered flow | Simple to schedule and change |
| Multi-person process spanning days | Flow Orchestration | Stages, work items and assignments built in |
| Processing very large record sets | Batch or queueable Apex | Chunked processing and explicit limit control |
| Callouts needing retries and parsing | Apex, called from Flow if needed | Better error handling and testability |
| Logic reused by flows, components and APIs | Apex service class | One tested implementation instead of copies |
| All-or-nothing updates across objects | Apex | Savepoints and precise rollback |
What mistakes show up most often?
The common failures are rarely about picking the wrong tool once. They come from small habits that compound over years of changes.
- Queries or updates inside loops, which hit governor limits as soon as a data load or integration sends records in bulk.
- Hard-coded record IDs, user names or queue names inside flows instead of variables, custom metadata or lookups.
- Flows with no fault paths, leaving users with cryptic errors and admins with nothing to trace.
- A new trigger and a new flow added to the same object by different people, with no agreed order.
- Apex written to pass the coverage gate with tests that assert nothing, so the percentage looks fine while behavior goes unchecked.
- Rebuilding the same logic in several flows when one subflow or invocable method would do.
In one rescue, Abstrakt found an industrial-services firm's flows firing 30 emails at once. Part of the fix was rebuilding task-creation logic around variables, replacing assignments that had been hard-coded. That kind of cleanup is ordinary optimization work, and it is cheaper before the org grows further.

