Trigger context variables are implicit variables Salesforce makes available inside every trigger. They tell you which event fired, which records are involved, and whether you’re running before or after the database commits — the information your handler needs to do the right thing.
The full list
| Variable | Type | What it gives you |
|---|---|---|
Trigger.new | List<SObject> | The new versions of the records (post-change). Writable in before, read-only in after. |
Trigger.old | List<SObject> | The pre-change versions. Available in update/delete/undelete only. Always read-only. |
Trigger.newMap | Map<Id, SObject> | Trigger.new indexed by Id. Null in before insert. |
Trigger.oldMap | Map<Id, SObject> | Trigger.old indexed by Id. Available in update/delete/undelete. |
Trigger.isInsert | Boolean | True if the event is an insert. |
Trigger.isUpdate | Boolean | True if the event is an update. |
Trigger.isDelete | Boolean | True if the event is a delete. |
Trigger.isUndelete | Boolean | True if the event is an undelete. |
Trigger.isBefore | Boolean | True in a before context. |
Trigger.isAfter | Boolean | True in an after context. |
Trigger.isExecuting | Boolean | True if the current Apex run is inside a trigger. |
Trigger.size | Integer | Number of records in the current invocation. |
Trigger.operationType | System.TriggerOperation enum | Single value capturing both timing and event (e.g. BEFORE_UPDATE, AFTER_INSERT). |
Routing with operationType
The modern way to dispatch context-specific logic is the operationType enum, introduced in Winter ‘17:
trigger AccountTrigger on Account (
before insert, before update,
after insert, after update, after delete, after undelete
) {
switch on Trigger.operationType {
when BEFORE_INSERT { AccountHandler.beforeInsert(Trigger.new); }
when BEFORE_UPDATE { AccountHandler.beforeUpdate(Trigger.new, Trigger.oldMap); }
when AFTER_INSERT { AccountHandler.afterInsert(Trigger.newMap); }
when AFTER_UPDATE { AccountHandler.afterUpdate(Trigger.newMap, Trigger.oldMap); }
when AFTER_DELETE { AccountHandler.afterDelete(Trigger.oldMap); }
when AFTER_UNDELETE { AccountHandler.afterUndelete(Trigger.newMap); }
}
}
A switch on operationType reads cleaner than nested isBefore && isInsert checks and exhausts all the cases for the compiler.
The traps
Trigger.newis read-only inafter— assigning to a field on a record inTrigger.newafter the save will throw at runtime.Trigger.oldMapis null inbefore insertandafter insert— there are no old records to compare against.Trigger.newis null in delete contexts — you only haveTrigger.oldandTrigger.oldMap.- Context variables outside a trigger? Not allowed.
Trigger.isExecutinglets you check before reading them in a shared utility class.
Common interview follow-ups
- Is
Trigger.newMapavailable inbefore insert? — No. Records don’t have Ids yet, so there’s nothing to map. - Can I modify
Trigger.old? — No. It’s always read-only. - What’s the difference between
Trigger.operationTypeandTrigger.isInsert/isBefore? —operationTypeis a single enum capturing both dimensions and is the recommended modern style.
Verified against: Apex Developer Guide — Trigger Context Variables. Last reviewed 2026-05-17.