Flow Transactional Boundaries
When to use this skill
Activate this skill when:
- You need to decide whether a piece of Flow work should run inline (Before-Save / After-Save) or be pushed to a new transaction (Scheduled Path, Platform Event, pause, subflow-after-callout).
- You're debugging a governor-limit exception in a flow that fires mid-transaction.
- You're building a flow that calls a callout or does heavy DML and need to know which pattern is safe.
- You're composing record-triggered flows with Apex triggers and need to predict the shared limit footprint.
- You're deciding between a Screen Flow pause and an Orchestration stage for a multi-day workflow.
Do NOT use this skill to pick Flow vs Apex (that's standards/decision-trees/automation-selection.md), or to pick a Flow subtype (that's standards/decision-trees/flow-pattern-selector.md — this skill is activated AFTER that tree).
Core concept — what is a "transaction" in Flow?
A Salesforce transaction is a unit of work bounded by:
- Start: a DML statement from a trigger, a user save from the UI, an Apex entry point (controller action, @HttpPost, future start), or a scheduler firing.
- End: the DML commits, or a rollback, or a governor-limit exception terminates the transaction.
Inside one transaction:
- SOQL queries count against the 100-query limit.
- DML rows count against the 10,000-row limit.
- CPU time counts against the 10-second limit (or 60s for async).
- All triggers, Before-Save flows, After-Save flows, validation rules, escalations, and Apex sharing share these limits.
Flow can either join an existing transaction or start its own. The choice changes everything about how the flow behaves under load and what happens on failure.
Transaction behavior per Flow entry point
Before-Save record-triggered flow
- Joins the triggering DML transaction.
- No DML elements allowed. Can only update the triggering record (via assignments), look up related records, and loop over collections.
- No callouts. Not supported in this context.
- No subflows that do DML. Autolaunched subflows that would do DML are blocked.
- Runs BEFORE the record is written, so changes to field values are free (no extra DML).
- Governor limits are shared with the rest of the transaction — but Before-Save is cheap, so the shared cost is usually negligible.
Use when: deriving field values on the same record. Setting Status__c from Amount + Stage. Copying account fields onto a case. Calculating a normalized phone.
After-Save record-triggered flow
- Joins the triggering DML transaction.
- All elements allowed: DML, callouts (must be wrapped in a
Transaction Control boundary or routed via a subflow to a pausable context), loops, subflows.
- DML row count adds to the shared 10,000-row limit with the trigger and any other after-save automations.
- Callouts from After-Save inline will throw
System.CalloutException: Callout from triggers are currently not supported. To do callouts, either (a) mark the flow "Run Asynchronously" (scheduled-path-of-zero-minutes), or (b) emit a Platform Event and subscribe async.
Use when: creating related records, posting to Chatter, sending emails synchronously, updating unrelated records in the same transaction.
Scheduled Path (on an after-save record-triggered flow)
- Starts a new transaction.
- Fresh governor limits. No DML sharing with the original trigger.
- The path fires at a configurable offset (+0 minutes = async-now, +30 days = SLA reminder).
- Callouts allowed.
- Replays independently of the original save. If the original save rolled back, the scheduled path never fires.
- If the record is deleted before the path fires, the path silently drops.
Use when: you want "eventually consistent" work that must not block the save; SLA reminders; fanout to related records; callouts.
Autolaunched flow called from Apex
- Joins the calling Apex transaction.
- Governor limits shared with Apex.
- Apex can call a flow via
Flow.Interview.createInterview(flowName, params).start() or via @InvocableMethod.
- Exceptions in the flow bubble up as
Flow.FlowException; wrap the Apex call in try/catch if the caller wants to continue on flow failure.
Use when: Apex orchestrates the transaction but needs a declarative subroutine (admin-maintainable logic).
Autolaunched flow called as a subflow
- Joins the parent flow's transaction.
- Shares limits with parent.
- A subflow cannot escape the parent's transactional context — if the parent is Before-Save, the subflow is too.
Screen flow (user-facing)
- Each save point in a screen flow (a DML element then a subsequent screen) is its own transaction.
- The commit happens when the user clicks Next past a screen following a DML element, or at the final Finish.
- If the user navigates away, uncommitted changes are lost.
- Pause elements persist the interview to the database and end the current transaction.
Screen flow with a Pause element
- Pause writes the
FlowInterview record, ends the current transaction, and schedules resume.
- On resume (user click, time trigger, Platform Event received), a new transaction begins.
- All state (variables, collections) is serialized and deserialized — large state can hit serialization limits.
Scheduled flow (fired by the clock, not by a record)
- Starts a new transaction.
- Fresh governor limits.
- Processes the record set defined in the flow's scheduler config; if the set is > 250k rows, the flow silently stalls on limits — escalate to Batchable Apex.
Platform-Event-triggered flow
- Fires on event delivery; each event delivery is a new transaction.
- High-Volume Platform Events are delivered in batches (up to 2,000 per subscriber execution).
- Fresh governor limits per batch.
- Ordering not guaranteed unless you use "Published After Commit" on the publisher side AND subscribe with a single subscriber.
Orchestration stage
- Each stage transition is a new transaction.
- Stage state persists in the
OrchestrationInstance record.
- Work items (human tasks) assigned at stage entry; stage advances only when all work items complete.
- Ideal for multi-day workflows that would overrun screen-flow session timeouts.
Recommended Workflow
- Read
standards/decision-trees/flow-pattern-selector.md to confirm the flow subtype.
- Classify the work as (a) field derivation on same record, (b) inline DML across records, (c) needs callouts, (d) must be delayed / scheduled, (e) spans multiple user sessions, (f) spans multiple humans.
- Pick the transaction boundary per the table in this skill.
- Draw the boundary diagram — list every DML, every callout, every subflow and mark which transaction it runs in.
- Compute the governor-limit budget per boundary — if a Before-Save joins a transaction already running 85 SOQL, your flow's 15 SOQL budget is tight.
- Plan idempotency — any work in a new transaction must be safe to run twice (scheduled paths, platform-event fanouts retry on failure).
- Document the boundary diagram in the flow description so downstream maintainers don't bypass the reasoning.
Key patterns
Pattern 1 — "Derive then act" split
Before-Save derives fields on the same record; After-Save (same flow or a sibling flow) creates related records.
[Trigger record updated]
│
▼
[Before-Save Flow] ← derives Normalized_Phone__c, Region__c
│ (same txn)
▼
[Record written to DB]
│ (same txn)
▼
[After-Save Flow] ← creates related Task + Chatter post
│ (same txn)
▼
[Transaction commits]
Savings: the Before-Save avoids a second DML for the field update — roughly a 90% cost reduction vs an After-Save that re-updates.
Pattern 2 — "Callout-required → Scheduled Path +0"
An After-Save flow needs to call an external service. Inline callouts are blocked in a trigger context. Route via a Scheduled Path with +0 minutes.
[Record inserted]
│
▼
[After-Save Flow entry]
│
▼
[Scheduled Path: +0 minutes, criteria: Status = 'Ready']
│ (new txn, fresh limits)
▼
[HTTP callout to vendor]
│
▼
[Update record with vendor ref]
Key detail: the +0 minutes doesn't mean "immediate" — the scheduler picks up the work, typically within 1–5 minutes. Not suitable for latency-sensitive needs.
Pattern 3 — Multi-day approval via Orchestration
Instead of a screen flow with pause elements (fragile, limited to one user's session), use an Orchestration with three stages: Legal Review → Procurement Review → Customer Sign-off. Each stage is a new transaction; each assigns a work item to a named user or queue.
See skills/flow/orchestration-flows for stage authoring.
Pattern 4 — "Platform Event fanout" for decoupled writes
A single trigger needs to update 5 unrelated objects. Instead of inline After-Save DML (which shares the 10,000-row limit with the trigger), publish one Platform Event and have 5 independent PE-triggered flows each handle one target. Each subscriber runs in its own transaction with fresh limits.
Bulk safety
- Before-Save flows are the most bulk-safe — no DML, simple element set, shared-limit impact is tiny.
- After-Save flows must be written with bulk DML in mind — use a Create Records element with a collection, never a loop with a DML inside.
- Scheduled Paths process records in batches of up to 200. If your record set per trigger event is larger than that, multiple scheduled-path executions run in parallel — plan for concurrent writes and set
Allow Concurrent Execution = true only when truly safe.
- Platform-Event-triggered flows receive events in batches of up to 2,000 per Standard PE, 10,000 per High-Volume PE. The flow's loop body runs once per event in the batch; loops must be bulk-safe.
- Scheduled flows run once per scheduled execution and process the query result set. If you use a Loop element, every DML inside is one-per-record — convert to a collection and do a single Update Records.
Error handling
- Before-Save: errors bubble as record save errors (user sees the Flow Error message as a save error). No fault path needed; the triggering DML is rolled back.
- After-Save inline: errors roll back the entire triggering transaction unless wrapped in a fault path that catches + logs. Always wire a Fault connector (see
skills/flow/fault-handling).
- Scheduled Path: errors end the scheduled-path transaction; the original save is already committed, so no rollback. Salesforce retries the scheduled-path execution up to 3 times with exponential backoff, then marks it failed. Use the Flow runtime error report.
- Platform-Event-triggered: on failure, the event is re-queued (Standard PE) or dropped (High-Volume PE with non-idempotent subscriber). Write subscribers to be idempotent — use an external-id field to dedupe.
- Screen flow pause: if resume fails, the interview stays in "Paused Error" state. Monitor via the Paused and Waiting Interviews list.
Well-Architected mapping
- Reliability — transaction boundary choice determines rollback scope. Before-Save failures roll back the user's save (often desirable for validation-like work). Scheduled Paths isolate failures (won't poison the original save). Pick based on whether the work is essential (inline) or eventually consistent (async).
- Performance — Before-Save is much cheaper than After-Save for field derivation. Scheduled Paths trade latency for limit isolation. Orchestrations add persistence overhead — use only when multi-day work genuinely needs it.
- Security — cross-transaction work (Scheduled Paths, Platform Events) runs as the "Automated Process" user or the record owner depending on version settings. CRUD/FLS posture may differ from the original trigger; verify with
skills/apex/apex-security-crud-fls principles.
Gotchas
See references/gotchas.md.
Testing
See skills/flow/flow-testing. Key testing concerns per boundary:
- Before-Save: assert field values on the returned record without DML.
- After-Save: assert DML results via SOQL after test setup commits.
- Scheduled Path: invoke
Test.startTest() / Test.stopTest() — scheduled-path records fire synchronously inside the test block.
- Platform-Event-triggered: use
Test.startTest() / Test.stopTest() to flush the event bus.
Official Sources Used
1---2name: flow-transactional-boundaries3description: Reason about when a Flow is inside the caller's transaction vs starts its own. Pick Before-Save vs After-Save vs Async Path vs Pause + Resume when transaction boundaries matter. Covers governor-limit sharing, DML sequencing, recoverability, and the exact semantics of each Flow entry point. NOT for choosing Flow vs Apex (use automation-selection.md). NOT for Flow-to-Flow invocation contracts (use subflows-and-reusability).4---56# Flow Transactional Boundaries78## When to use this skill910Activate this skill when:1112- You need to decide whether a piece of Flow work should run **inline** (Before-Save / After-Save) or be pushed to a **new transaction** (Scheduled Path, Platform Event, pause, subflow-after-callout).13- You're debugging a governor-limit exception in a flow that fires mid-transaction.14- You're building a flow that calls a callout or does heavy DML and need to know which pattern is safe.15- You're composing record-triggered flows with Apex triggers and need to predict the shared limit footprint.16- You're deciding between a Screen Flow pause and an Orchestration stage for a multi-day workflow.1718Do NOT use this skill to pick Flow vs Apex (that's `standards/decision-trees/automation-selection.md`), or to pick a Flow subtype (that's `standards/decision-trees/flow-pattern-selector.md` — this skill is activated AFTER that tree).1920## Core concept — what is a "transaction" in Flow?2122A Salesforce transaction is a unit of work bounded by:2324- **Start:** a DML statement from a trigger, a user save from the UI, an Apex entry point (controller action, @HttpPost, future start), or a scheduler firing.25- **End:** the DML commits, or a rollback, or a governor-limit exception terminates the transaction.2627Inside one transaction:28- SOQL queries count against the 100-query limit.29- DML rows count against the 10,000-row limit.30- CPU time counts against the 10-second limit (or 60s for async).31- All triggers, Before-Save flows, After-Save flows, validation rules, escalations, and Apex sharing share these limits.3233Flow can either **join** an existing transaction or **start its own**. The choice changes everything about how the flow behaves under load and what happens on failure.3435## Transaction behavior per Flow entry point3637### Before-Save record-triggered flow3839- Joins the triggering DML transaction.40- **No DML elements allowed.** Can only update the triggering record (via assignments), look up related records, and loop over collections.41- **No callouts.** Not supported in this context.42- **No subflows that do DML.** Autolaunched subflows that would do DML are blocked.43- Runs BEFORE the record is written, so changes to field values are free (no extra DML).44- Governor limits are **shared** with the rest of the transaction — but Before-Save is cheap, so the shared cost is usually negligible.4546Use when: deriving field values on the same record. Setting `Status__c` from `Amount` + `Stage`. Copying account fields onto a case. Calculating a normalized phone.4748### After-Save record-triggered flow4950- Joins the triggering DML transaction.51- All elements allowed: DML, callouts (must be wrapped in a `Transaction Control` boundary or routed via a subflow to a pausable context), loops, subflows.52- DML row count **adds to** the shared 10,000-row limit with the trigger and any other after-save automations.53- **Callouts from After-Save inline will throw `System.CalloutException: Callout from triggers are currently not supported`.** To do callouts, either (a) mark the flow "Run Asynchronously" (scheduled-path-of-zero-minutes), or (b) emit a Platform Event and subscribe async.5455Use when: creating related records, posting to Chatter, sending emails synchronously, updating unrelated records in the same transaction.5657### Scheduled Path (on an after-save record-triggered flow)5859- Starts a **new transaction**.60- Fresh governor limits. No DML sharing with the original trigger.61- The path fires at a configurable offset (+0 minutes = async-now, +30 days = SLA reminder).62- Callouts allowed.63- **Replays independently of the original save.** If the original save rolled back, the scheduled path never fires.64- If the record is deleted before the path fires, the path silently drops.6566Use when: you want "eventually consistent" work that must not block the save; SLA reminders; fanout to related records; callouts.6768### Autolaunched flow called from Apex6970- Joins the calling Apex transaction.71- Governor limits shared with Apex.72- Apex can call a flow via `Flow.Interview.createInterview(flowName, params).start()` or via `@InvocableMethod`.73- Exceptions in the flow bubble up as `Flow.FlowException`; wrap the Apex call in try/catch if the caller wants to continue on flow failure.7475Use when: Apex orchestrates the transaction but needs a declarative subroutine (admin-maintainable logic).7677### Autolaunched flow called as a subflow7879- Joins the parent flow's transaction.80- Shares limits with parent.81- **A subflow cannot escape the parent's transactional context** — if the parent is Before-Save, the subflow is too.8283### Screen flow (user-facing)8485- Each **save point** in a screen flow (a DML element then a subsequent screen) is its own transaction.86- The commit happens when the user clicks Next past a screen following a DML element, or at the final Finish.87- If the user navigates away, uncommitted changes are lost.88- Pause elements **persist the interview to the database** and end the current transaction.8990### Screen flow with a Pause element9192- Pause writes the `FlowInterview` record, ends the current transaction, and schedules resume.93- On resume (user click, time trigger, Platform Event received), a **new transaction** begins.94- All state (variables, collections) is serialized and deserialized — large state can hit serialization limits.9596### Scheduled flow (fired by the clock, not by a record)9798- Starts a new transaction.99- Fresh governor limits.100- Processes the record set defined in the flow's scheduler config; if the set is > 250k rows, the flow silently stalls on limits — escalate to Batchable Apex.101102### Platform-Event-triggered flow103104- Fires on event delivery; each event delivery is a **new transaction**.105- High-Volume Platform Events are delivered in batches (up to 2,000 per subscriber execution).106- Fresh governor limits per batch.107- **Ordering not guaranteed** unless you use "Published After Commit" on the publisher side AND subscribe with a single subscriber.108109### Orchestration stage110111- Each stage transition is a new transaction.112- Stage state persists in the `OrchestrationInstance` record.113- Work items (human tasks) assigned at stage entry; stage advances only when all work items complete.114- Ideal for multi-day workflows that would overrun screen-flow session timeouts.115116## Recommended Workflow1171181. **Read `standards/decision-trees/flow-pattern-selector.md`** to confirm the flow subtype.1192. **Classify the work** as (a) field derivation on same record, (b) inline DML across records, (c) needs callouts, (d) must be delayed / scheduled, (e) spans multiple user sessions, (f) spans multiple humans.1203. **Pick the transaction boundary** per the table in this skill.1214. **Draw the boundary diagram** — list every DML, every callout, every subflow and mark which transaction it runs in.1225. **Compute the governor-limit budget per boundary** — if a Before-Save joins a transaction already running 85 SOQL, your flow's 15 SOQL budget is tight.1236. **Plan idempotency** — any work in a new transaction must be safe to run twice (scheduled paths, platform-event fanouts retry on failure).1247. **Document the boundary diagram in the flow description** so downstream maintainers don't bypass the reasoning.125126## Key patterns127128### Pattern 1 — "Derive then act" split129130Before-Save derives fields on the same record; After-Save (same flow or a sibling flow) creates related records.131132```133[Trigger record updated]134 │135 ▼136[Before-Save Flow] ← derives Normalized_Phone__c, Region__c137 │ (same txn)138 ▼139[Record written to DB]140 │ (same txn)141 ▼142[After-Save Flow] ← creates related Task + Chatter post143 │ (same txn)144 ▼145[Transaction commits]146```147148Savings: the Before-Save avoids a second DML for the field update — roughly a 90% cost reduction vs an After-Save that re-updates.149150### Pattern 2 — "Callout-required → Scheduled Path +0"151152An After-Save flow needs to call an external service. Inline callouts are blocked in a trigger context. Route via a Scheduled Path with +0 minutes.153154```155[Record inserted]156 │157 ▼158[After-Save Flow entry]159 │160 ▼161[Scheduled Path: +0 minutes, criteria: Status = 'Ready']162 │ (new txn, fresh limits)163 ▼164[HTTP callout to vendor]165 │166 ▼167[Update record with vendor ref]168```169170Key detail: the +0 minutes doesn't mean "immediate" — the scheduler picks up the work, typically within 1–5 minutes. Not suitable for latency-sensitive needs.171172### Pattern 3 — Multi-day approval via Orchestration173174Instead of a screen flow with pause elements (fragile, limited to one user's session), use an Orchestration with three stages: Legal Review → Procurement Review → Customer Sign-off. Each stage is a new transaction; each assigns a work item to a named user or queue.175176See `skills/flow/orchestration-flows` for stage authoring.177178### Pattern 4 — "Platform Event fanout" for decoupled writes179180A single trigger needs to update 5 unrelated objects. Instead of inline After-Save DML (which shares the 10,000-row limit with the trigger), publish one Platform Event and have 5 independent PE-triggered flows each handle one target. Each subscriber runs in its own transaction with fresh limits.181182## Bulk safety183184- **Before-Save flows are the most bulk-safe** — no DML, simple element set, shared-limit impact is tiny.185- **After-Save flows must be written with bulk DML in mind** — use a Create Records element with a collection, never a loop with a DML inside.186- **Scheduled Paths process records in batches of up to 200.** If your record set per trigger event is larger than that, multiple scheduled-path executions run in parallel — plan for concurrent writes and set `Allow Concurrent Execution = true` only when truly safe.187- **Platform-Event-triggered flows** receive events in batches of up to 2,000 per Standard PE, 10,000 per High-Volume PE. The flow's loop body runs once per event in the batch; loops must be bulk-safe.188- **Scheduled flows run once per scheduled execution** and process the query result set. If you use a Loop element, every DML inside is one-per-record — convert to a collection and do a single Update Records.189190## Error handling191192- **Before-Save:** errors bubble as record save errors (user sees the Flow Error message as a save error). No fault path needed; the triggering DML is rolled back.193- **After-Save inline:** errors roll back the entire triggering transaction unless wrapped in a fault path that catches + logs. Always wire a Fault connector (see `skills/flow/fault-handling`).194- **Scheduled Path:** errors end the scheduled-path transaction; the original save is already committed, so no rollback. Salesforce retries the scheduled-path execution up to 3 times with exponential backoff, then marks it failed. Use the Flow runtime error report.195- **Platform-Event-triggered:** on failure, the event is re-queued (Standard PE) or dropped (High-Volume PE with non-idempotent subscriber). Write subscribers to be idempotent — use an external-id field to dedupe.196- **Screen flow pause:** if resume fails, the interview stays in "Paused Error" state. Monitor via the Paused and Waiting Interviews list.197198## Well-Architected mapping199200- **Reliability** — transaction boundary choice determines rollback scope. Before-Save failures roll back the user's save (often desirable for validation-like work). Scheduled Paths isolate failures (won't poison the original save). Pick based on whether the work is essential (inline) or eventually consistent (async).201- **Performance** — Before-Save is much cheaper than After-Save for field derivation. Scheduled Paths trade latency for limit isolation. Orchestrations add persistence overhead — use only when multi-day work genuinely needs it.202- **Security** — cross-transaction work (Scheduled Paths, Platform Events) runs as the "Automated Process" user or the record owner depending on version settings. CRUD/FLS posture may differ from the original trigger; verify with `skills/apex/apex-security-crud-fls` principles.203204## Gotchas205206See `references/gotchas.md`.207208## Testing209210See `skills/flow/flow-testing`. Key testing concerns per boundary:211212- Before-Save: assert field values on the returned record without DML.213- After-Save: assert DML results via SOQL after test setup commits.214- Scheduled Path: invoke `Test.startTest()` / `Test.stopTest()` — scheduled-path records fire synchronously inside the test block.215- Platform-Event-triggered: use `Test.startTest() / Test.stopTest()` to flush the event bus.216217## Official Sources Used218219- Salesforce Help — Flow Run-Time Behavior: https://help.salesforce.com/s/articleView?id=sf.flow_concepts_runtime.htm220- Salesforce Developer — Trigger Order of Execution: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_order_of_execution.htm221- Salesforce Help — Scheduled Paths in Record-Triggered Flows: https://help.salesforce.com/s/articleView?id=sf.flow_concepts_trigger_scheduled_path.htm222- Salesforce Developer — Platform Events Developer Guide: https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/223- Salesforce Architects — Well-Architected Framework: https://architect.salesforce.com/design/architecture-framework/well-architected