How to manage Salesforce Flow transactions and rollbacks

If you’ve ever spent a Sunday night fixing data because a process crashed halfway through, you know how tricky Salesforce Flow transactions can be. It’s one of those things that seems simple until you’re dealing with a complex record-triggered flow that’s hitting governor limits or rolling back changes you actually wanted to keep.

Understanding Salesforce Flow transactions and boundaries

Here’s the deal: Salesforce works on an “all or nothing” basis. When a Flow starts, it joins a transaction. If anything goes wrong and you don’t handle the error, Salesforce hits the panic button and rolls everything back. This is usually a good thing because it prevents partial data, but it can be a massive headache when you’re trying to debug what actually happened.

I’ve seen teams struggle with this because they don’t realize where the transaction starts and ends. For example, a “before-save” flow is basically part of the record’s initial save. It doesn’t do its own DML, so it’s super fast. But an “after-save” flow is a different beast. It runs in the same transaction as the initial save, meaning if your flow fails, the record that triggered it doesn’t get saved either. You can learn more about ensuring data integrity to avoid these common pitfalls.

  • Synchronous Flows: These run right now, in the same bucket of resources as whatever started them.
  • Asynchronous Paths: These happen later in their own separate transaction. This is your best friend when you need to do something “heavy” like calling an external API.
  • Wait Elements: When a Flow hits a Pause or Wait element, the current transaction ends and commits. When it resumes, it’s a brand new transaction.

Pro tips for managing Salesforce Flow transactions

So, how do we actually control this behavior? Honestly, most teams get this wrong by relying on the default “unhandled exception” email. That’s not a strategy; that’s a prayer. You need to be intentional about how you handle failures and where you break your work into smaller chunks.

1) Use Fault Paths for more than just error messages

Every DML element (Create, Update, Delete) has a Fault connector. Use it. But don’t just show a screen saying “Oops.” I always recommend logging the error to a custom “Error Log” object. This way, even if the main transaction rolls back, you can sometimes use a Platform Event to publish that log so it stays in the database. It’s also a good idea to look at error handling for specific actions like emails to keep things running smoothly.

In my experience, the biggest mistake people make is assuming a Fault Path fixes everything. It doesn’t. If your Fault Path doesn’t lead to a screen or a log record, you’re still flying blind when things go sideways.

2) Decouple risky work

If you have a piece of logic that is likely to fail – like an integration call or a complex calculation – don’t let it kill your main transaction. You can move that work into a separate Salesforce Flow transaction by using Platform Events or Asynchronous paths. This keeps the primary record update safe even if the secondary stuff fails. If you’re wondering which tool to use, check out this guide on when to use different asynchronous types.

3) Invocable Apex and Savepoints

Sometimes Flow isn’t enough, and you need to call Apex. You can use Database.setSavepoint() and Database.rollback() in your code, but be careful. These savepoints apply to the whole transaction. If you roll back in Apex, you’re rolling back everything the Flow did up to that point too. It’s a powerful tool, but it’s like using a sledgehammer to hang a picture frame. Use it only when you’ve got a very specific reason.


public class FlowAsyncProcessor {
    @InvocableMethod(label='Run Heavy DML')
    public static void runAsync(List<Id> recordIds) {
        // Enqueueing a job creates a new transaction boundary
        System.enqueueJob(new MyQueueableJob(recordIds));
    }
}

Key Takeaways for Salesforce Flow transactions

  • Transaction Limits: Remember that all elements in a single transaction share the same governor limits. If your Flow is huge, break it up.
  • Fault Paths: These are your safety net. Use them to log errors, not just to show a pretty message.
  • Platform Events: These are great for “fire and forget” logic that shouldn’t stop the main process.
  • Wait Elements: Use these to explicitly end one transaction and start another if you’re hitting limits.

Wrapping it up

At the end of the day, managing Salesforce Flow transactions is about knowing when to stay in the current boat and when to jump into a new one. Start by mapping out your transaction boundaries before you build. If you’ve got a lot of DML happening in one go, ask yourself: “What happens if this fails at step 4?” If the answer is “a giant mess,” then it’s time to look at decoupling your logic. Keep it simple, log your errors, and don’t be afraid to use async paths when things get heavy.