With multiple options available, the decision framework matters more than knowing all the options.
Decision criteria, ordered by importance:
1. Maintainer. Who will maintain this?
- Admin-only team -> Flow.
- Mixed admin + dev team -> Flow at orchestration, Apex Invocable for heavy lifting.
- Dev-heavy team -> Apex Trigger via Trigger Framework.
2. Performance. What's the expected volume?
- Single-record save, low frequency -> Flow is fine.
- 200-record bulk DML, 100k records/day -> Apex Trigger (better bulk control).
- 10M-record nightly batch -> Apex Batch, definitely.
3. Recursion / re-entry awareness. Will the automation potentially fire itself recursively?
- Simple chains -> Flow with
Equals_Changed_Todecisions. - Complex recursion -> Apex Trigger with static guard.
4. Cross-object atomicity. Does the operation need to update multiple unrelated records atomically?
- Within parent-child via master-detail -> Flow handles fine.
- Multi-object transactional logic -> Apex Trigger (clearer transaction control).
5. Custom error handling. Need partial-success or custom rollback?
- Standard errors -> Flow's "Fault Path" works.
- Per-record success/failure with detailed logging -> Apex
Database.SaveResultpatterns.
6. Sharing model. Need to write to __Share tables?
- Apex Managed Sharing only — flows can't.
7. Callouts. Need to call external services?
- Simple callout from a flow -> Flow's HTTP Callout action works.
- Complex multi-callout orchestration -> Apex.
8. Specific platform features.
- Validation Rule for save-time invariants.
- Roll-Up Summary for parent aggregation.
- Path for stage guidance.
9. Testability. How testable does this need to be?
- Mission-critical (touches money, audit data) -> Apex with comprehensive tests.
- UX nudge or simple update -> Flow with Debug Run.
10. Future evolution. Will this likely grow in complexity?
- Will probably stay simple -> Flow.
- Will likely accumulate cross-cutting concerns -> Apex Trigger Framework.
Anti-patterns to avoid:
- Multiple automations on the same object trigger fighting each other. Pick one owner per logical change.
- A flow with 60+ elements. Past a certain size, refactor into Apex.
- Apex doing what one validation rule could do. Don't over-engineer.
- Process Builder for new work. End-of-life. Use Flow.
Recommended pattern for non-trivial automations:
Record-Triggered Flow (orchestration, simple decisions) | -> calls Apex Invocable Method (heavy logic, bulkified) | -> uses Repository / Service / Selector layers | -> tested with mocks and 200-record bulk tests
This gives admins flexibility at the orchestration layer while developers own the depth.
The senior insight: the right answer is rarely "all Apex" or "all Flow". It's "Flow for what Flow does well; Apex for what Apex does well; design the boundary deliberately."
