Salesforce Dictionary - Free Salesforce GlossarySalesforce Dictionary
Full Transaction, Apex entry
How-to guide

Use Savepoints to add partial rollback to Apex

Add a Savepoint to your Apex transaction so you can attempt a risky DML and roll back to a known good state if it fails, without aborting the entire transaction.

By Dipojjal Chakrabarti · Founder & Editor, Salesforce DictionaryLast updated May 26, 2026

Add a Savepoint to your Apex transaction so you can attempt a risky DML and roll back to a known good state if it fails, without aborting the entire transaction.

  1. Identify the rollback boundary

    Pick the point in your code where the state is consistent and you would be willing to discard subsequent work if needed. This is usually right before a multi-step DML operation that might partially fail.

  2. Create the savepoint

    Call Savepoint sp = Database.setSavepoint(); at the rollback boundary. The handle holds the transaction state at that point.

  3. Wrap the risky DML in try/catch

    Try the DML operations you want to compensate. Catch the DmlException (or specific exception type). Inside the catch, call Database.rollback(sp); to revert to the savepoint state.

  4. Run compensating logic

    After the rollback, optionally execute an alternative path: log the failure, insert a fallback record, or notify a queue. The transaction continues from the savepoint, not from the start.

  5. Test the partial rollback in apex tests

    Write a unit test that forces the risky DML to fail (a validation rule, a unique constraint, a missing required field). Verify the records before the savepoint are still present and the compensating logic ran.

  6. Mind the SOQL counter

    Remember that Database.rollback() does not reset the SOQL query counter. If your savepoint code ran many queries, you can still hit the per-transaction limit even after rolling back.

Key options
Savepointremember

Handle returned by Database.setSavepoint(); marks a known good state to roll back to.

allOrNone flagremember

Parameter on Database.insert/update/delete that controls whether one bad row rolls back the whole batch. Independent from Savepoints.

Async transactionremember

Queueable, Future, Batch, Scheduled. Each runs in its own transaction with its own savepoint scope.

Static variableremember

Class-level field that lives for one transaction. Useful for caching and recursion guards inside the transaction.

Gotchas
  • Database.rollback(sp) does not reset the SOQL or DML statement counter. You can roll back and still exceed the transaction limit on retry.
  • Uncaught exceptions roll back the entire transaction, even DML performed before a savepoint. Use try/catch deliberately at the boundary that needs to handle the failure.
  • Future, Queueable, and Batch jobs queue from a transaction but execute in their own transactions later. Limits on the calling transaction do not transfer; limits on the callee transaction start fresh.
  • Trigger order of execution causes recursive saves to look like the same transaction even though logically they are nested calls. Use a static boolean guard to prevent infinite recursion.

See the full Transaction, Apex entry

Transaction, Apex includes the definition, worked example, deep dive, related terms, and a quiz.