Skip to main content

SF-0334 · Concept · Medium

What is a recursive Trigger?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

A recursive trigger is a trigger that ends up firing itself — directly or indirectly — because some logic inside it issues DML that hits the same object the trigger is bound to. Without a guard, the chain repeats until you blow a governor limit (Too many SOQL queries, CPU time limit exceeded, or Maximum trigger depth exceeded).

How it happens

Consider an after update trigger on Account that recalculates a field and writes the result back:

trigger AccountTrigger on Account (after update) {
    List<Account> toUpdate = new List<Account>();
    for (Account a : Trigger.new) {
        Account copy = new Account(Id = a.Id);
        copy.Health_Score__c = a.AnnualRevenue / 1000;
        toUpdate.add(copy);
    }
    update toUpdate; // fires AccountTrigger again
}

The update toUpdate line triggers another after update invocation. That invocation runs the same logic, issues another update, fires the trigger again, and so on. Salesforce’s hard ceiling — 16 levels of trigger recursion — eventually throws, but you’ll typically hit the SOQL or DML governor limit first.

When recursion is legitimate vs accidental

Accidental recursion is the kind above — you write a record back and the same trigger re-runs your already-completed work.

Legitimate recursion happens when a trigger updates a different object whose trigger updates a third object that eventually updates the first. This is a real call graph, not a loop, but it can still revisit the original trigger context.

Recursion can also happen via workflow field updates and processes that re-fire triggers after the initial save (Trigger.isExecuting will still be true, but Trigger.isTriggerExecutionRecursive won’t help — that flag doesn’t exist).

The symptoms in production

  • System.LimitException: Too many SOQL queries: 101 — the trigger ran 101 times, each issuing one query.
  • System.LimitException: Apex CPU time limit exceeded — endless re-entry.
  • Maximum trigger depth exceeded — Salesforce’s hard cap of 16.
  • Data inconsistency where before triggers re-mutate fields the platform already wrote.

What Trigger.isExecuting does not tell you

Trigger.isExecuting is true whenever you’re inside any trigger context — not specifically whether this trigger has already run in this transaction. You need a static variable for that. The fix is covered separately in How to avoid recursive triggers.

Common interview follow-ups

  • What’s the max recursion depth? — 16 levels, enforced by the platform as Maximum trigger depth exceeded.
  • Do before and after triggers both recurse? — Yes. Both fire again on any DML against the same object.
  • Does Flow recursion count toward the trigger depth? — Workflow field updates and processes that fire after the save can re-enter triggers, but they count against their own re-execution limit (usually 5 levels for workflow recursion).

Verified against: Apex Developer Guide — Triggers and Order of Execution, Execution Governors and Limits. Last reviewed 2026-05-17.