The Problem: Triggers That Call Themselves
If you’ve ever written a trigger that updates a record, only to find that update firing the same trigger again… and again… you’ve met recursion.
Even experienced developers get caught in this — especially when working across multiple objects or in complex update scenarios.
Why Recursive Triggers Happen
Salesforce executes triggers each time a DML operation occurs, including if that DML is initiated from within a trigger.
trigger AccountTrigger on Account (after update) {
for (Account acc : Trigger.new) {
acc.Description = 'Updated internally';
update acc; // This line causes recursion
}
}
This will call the same trigger again — causing an infinite loop or hitting governor limits.
How to Prevent Trigger Recursion
1. Use a Static Variable
Create a static Boolean flag in a helper class:
public class TriggerHelper {
public static Boolean isFirstRun = true;
}
In your trigger:
trigger AccountTrigger on Account (after update) {
if (TriggerHelper.isFirstRun) {
TriggerHelper.isFirstRun = false;
// safe update logic
List<Account> toUpdate = new List<Account>();
for (Account acc : Trigger.new) {
acc.Description = 'Updated internally';
toUpdate.add(acc);
}
update toUpdate;
}
}
This ensures the logic runs only once per transaction.
2. Use a Trigger Framework
If your org is growing, it’s better to adopt a framework-based pattern.
public class TriggerControl {
public static Set<Id> processedIds = new Set<Id();
}
trigger ContactTrigger on Contact (before update) {
for (Contact con : Trigger.new) {
if (!TriggerControl.processedIds.contains(con.Id)) {
// Business logic here
TriggerControl.processedIds.add(con.Id);
}
}
}
Use Set<Id> to track which records have been processed. Much better for batch-safe logic.
