---
name: salesforce-automation
description: Design, build and review Salesforce automation — choosing between Flow (record-triggered, scheduled, screen, autolaunched, platform-event-triggered), Apex triggers, and Approval Processes/Orchestrator; before-save vs after-save flows, entry criteria, bulk-safe flow patterns, subflows and invocable actions, error handling and fault paths, flow testing, governance for one-automation-per-object, and migrating Workflow Rules and Process Builder to Flow. Use this whenever the user asks whether to use Flow or Apex, how to build or debug a Flow, hits flow limits or "too many SOQL queries" from flows, asks about record-triggered flow order, migrating workflow rules/process builder, approval processes, scheduled jobs, or how to structure automation on an object. Also apply it when reviewing flows or automation architecture.
metadata:
  technology: Salesforce
  type: development
---

# Salesforce Automation

The platform gives three ways to automate the same thing, and orgs rot when all three are used on one object with no owner. The goal is a **documented automation strategy per object**: which tool handles which kind of logic, in which order, with bulk safety and fault handling designed in.

## 1. Tool selection

| Requirement | Tool | Why |
|---|---|---|
| Set/validate fields on the same record before it saves | **Record-triggered Flow — before save** (or a before-trigger if Apex already owns the object) | Fastest option; no DML; runs before validation rules |
| Create/update related records, send emails/notifications, call actions after save | **Record-triggered Flow — after save** | Declarative, admin-maintainable |
| Complex logic: cross-object aggregation, recursion control, large volumes, external callouts with retries, reusable service methods | **Apex trigger handler → Service** | Performance, testability, limits control |
| User-guided multi-step input | **Screen Flow** (+ LWC steps when needed) | Wizards, guided selling, case deflection |
| Time-based / batch on a schedule | **Scheduled Flow** (< ~250k records/day) or **Batch Apex** (above that, or complex) | Scheduled flow has record-count limits |
| React to Platform Events / CDC | **Platform Event–Triggered Flow** for simple; **Apex event trigger** for complex/idempotency | Both at-least-once |
| Approvals with steps, delegates, parallel/serial | **Approval Process**; multi-stage cross-object workflows → **Flow Orchestrator** | — |
| Reusable logic callable from Flow | **Invocable Apex** (`@InvocableMethod`) exposing a bulk `List<Request>` signature | One Apex method, many flows |
| Workflow Rules / Process Builder | **Retired** — migrate to Flow with the Migrate to Flow tool, then refactor | No new ones can be created |

Decision heuristic: **declarative until it hurts**. Move to Apex when the flow needs loops over collections > ~2k, nested loops, more than ~3 record-triggered flows on the object, complex error recovery, or when admins can no longer explain it.

## 2. One-object automation strategy (write this down)

```
Object: Order__c
Before-save Flow:  Order_Before_Save   — defaults, formulas that can't be formula fields, simple validation
After-save Flow:   Order_After_Save    — notifications, related-record creation (bulk-safe), platform event publish
Apex:              OrderTriggerHandler — pricing recalculation, cross-object roll-ups, integration callouts (async)
Validation Rules:  data integrity only, no cross-object queries
Scheduled:         Order_Aging_Daily (Scheduled Flow) — status escalation
Order of ops owner: <team>; changes require ADR
```

Rules:
- **Max one before-save and one after-save record-triggered flow per object** (Salesforce's own recommendation); route by entry criteria and decision elements, or subflows per business area.
- Flow trigger order via **Trigger Order** on the flow when multiple exist (transitional only).
- Apex and Flow on the same object: decide which owns *what kind* of logic; never both mutating the same fields.
- Keep validation in validation rules or before-save flows, not after-save.

## 3. Building bulk-safe flows

Record-triggered flows run once per batch of up to 200 records **per element path**, but Get/Create/Update/Delete inside loops execute per iteration — the same SOQL-in-loop problem as Apex.

- **Never put a Get/Create/Update/Delete inside a Loop.** Collect into a collection variable in the loop; do a single DML after it. Use *Assignment → add to collection*, then one *Update Records* on the collection.
- **Entry conditions** on the Start element (and "only when a record is updated to meet the condition") so the flow doesn't run for unrelated edits — this is your recursion guard and your limits saver.
- **Before-save for same-record updates**: use `$Record` assignments, no Update element needed, no DML consumed.
- **Get Records** with filters on indexed fields; never "Get all then filter in a loop". Use *Transform* and collection filter elements.
- **Formulas over Decision chains** where readable; **Decision** for branching; avoid 8-level nested decisions — extract subflows.
- **Subflows** for reuse and readability; pass input/output variables explicitly; version subflows independently.
- **Invocable Apex** when the flow needs: aggregation, external callout with retry, complex text/date math, or > ~2k iterations.
- **Async path** (Run Asynchronously) for callouts and for non-critical work that shouldn't block the save; remember it runs in a separate transaction (different limits, eventual).
- **Scheduled paths** (e.g. "3 days after Close Date") for time-based actions instead of separate scheduled flows where they belong to a record event.
- Watch flow-specific limits: 2,000 executed elements per interview, SOQL/DML shared with Apex in the same transaction, 250k scheduled-flow records/day per org.

## 4. Error handling

- **Fault connectors** on every DML/Get/Action element → a shared *Fault* subflow that logs to a custom object/Platform Event (via invocable logger) and, for screen flows, shows a friendly message.
- Screen flows: validate inputs on the screen (component validation, regex); don't let a DML failure be the first validation.
- **Roll back**: a record-triggered flow's fault fails the whole transaction unless on an async path; design async paths idempotent because they retry.
- Platform-event-triggered flows run as **Automated Process** user — grant it permissions; failures are visible in Setup → Flow → Paused and Failed Interviews; monitor them.
- Enable **Flow error emails** to a distribution list, not the last modifying admin.

## 5. Screen flows (user-facing)

- One question per screen where possible; progress indicator via a header component; `Previous` allowed unless data was committed.
- Use **reactive screen components** and formulas to avoid extra screens; LWC screen components (see `lwc-development`) for anything Flow can't render (typeahead, complex tables).
- Collect data → single *Create/Update* at the end; show a confirmation screen with created record links.
- Embed via Lightning page, quick action, Experience Cloud, utility bar, or Slack; pass `recordId` as an input variable.
- Accessibility: labels, help text, required markers; test with keyboard and screen reader like any UI.

## 6. Approvals and orchestration

- **Approval Process** for single-object, step-based approvals with delegates/reassignment; entry criteria + field updates on approve/reject; lock records while pending.
- **Flow Orchestrator** for multi-stage, multi-user, multi-object work (onboarding, claim handling) with interactive steps assigned to queues/users and background steps calling flows/Apex.
- Keep approval logic out of record-triggered flows — let the approval process own state transitions; flows react to `Approval_Status__c` changes.

## 7. Testing and deployment

- **Flow Tests** (Setup → Flow → Tests) for record-triggered flows: create/update scenarios with assertions; run in CI via `sf flow test run` (where available) or the Apex tests that exercise the object.
- Apex tests that insert/update the object also cover flows — assert the flow's outcomes there (fields set, records created) for bulk (200) and edge cases.
- Debug with **Flow Debug** (rollback mode, run as another user), Debug Logs (`FLOW_*` events), and the flow *Time Stamp* elements in dev.
- Deploy flows **active** via metadata (`FlowDefinition` deprecated; set `status` Active in the `Flow` metadata, allow "Deploy inactive/active" settings); clean up old versions (keep ≤ 5).
- Version notes in the flow description: what changed, ticket, author.

## 8. Migration playbook (Workflow Rules / Process Builder → Flow)

1. Inventory: export all WFR/PB per object with criteria, actions, and active status (Metadata API / `sf project retrieve` on `Workflow`, `Flow` with `processType=Workflow`).
2. Group by object; design the target one-before / one-after flow per object with entry criteria mirroring the rule criteria.
3. Use **Migrate to Flow** for mechanical conversion, then **refactor**: merge into the object's consolidated flow, replace field updates with before-save assignments, move time-based actions to scheduled paths.
4. Deactivate the source rule only after the flow is live and verified in a sandbox with bulk data; keep a rollback path (reactivate) for one release.
5. Delete retired rules after two releases; update the automation strategy doc.

## 9. Governance checklist

- [ ] Automation strategy documented per object (tool ownership, order)
- [ ] ≤ 1 before-save + 1 after-save record-triggered flow per object, or a dated plan to get there
- [ ] Every DML/Get/Action element has a fault path to the shared fault subflow
- [ ] No DML/Get inside loops; entry conditions set; bulk-tested with 200 records
- [ ] Naming: `<Object>_<Trigger>_<Purpose>` flows; API names without spaces; descriptions filled
- [ ] Flow tests or covering Apex tests exist; old versions pruned
- [ ] No Workflow Rules / Process Builders remaining active

## Anti-patterns to reject

- Get/Create/Update inside a Loop element.
- Five record-triggered flows plus a trigger on one object with no ordering decision.
- After-save flow updating the same record's fields (should be before-save).
- Flows with no fault connectors; errors emailed to whoever last saved.
- Screen flow doing DML on every screen.
- Process Builder or Workflow Rule created or extended "temporarily".
- Recursion "fixed" by a checkbox field toggled by the flow itself.
- Hardcoded Ids, emails, or URLs in flows — use Custom Metadata / Custom Labels / `$Setup`.
- Flows so large the canvas needs a map; extract subflows or move to Apex.
