Salesforce Dictionary - Free Salesforce GlossarySalesforce Dictionary
Full Trigger Context Variable entry
How-to guide

Use trigger context variables in a bulkified Apex trigger

Trigger context variables are best understood by writing a trigger that uses them. The steps below walk through the canonical patterns: detect a field change, prevent recursion, and split before vs after work.

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

Trigger context variables are best understood by writing a trigger that uses them. The steps below walk through the canonical patterns: detect a field change, prevent recursion, and split before vs after work.

  1. Branch on event type with the boolean flags

    Inside the trigger, branch on Trigger.isBefore + Trigger.isInsert vs Trigger.isAfter + Trigger.isUpdate to handle each context. Combine the timing flag and the event flag explicitly; do not assume a single trigger only ever runs one event.

  2. Iterate Trigger.new and read Trigger.oldMap by Id

    For an update trigger, iterate Trigger.new with a for-each loop and look up the matching old version with Trigger.oldMap.get(rec.Id). Compare the fields you care about. Build a List of records that need follow-up work outside the loop.

  3. Move SOQL and DML outside the loop

    Collect Ids or sObjects inside the loop. Run SOQL once over the collected Ids. Run DML once over the collected list. Bulkified trigger code processes 200 records in the same query and DML budget as 1 record.

  4. Guard against recursion with a static set

    Add a static Set of Id to a helper class that the trigger calls. Before processing a record, check whether its Id is in the set; if so, skip. After processing, add the Id. Recursion guards are essential for triggers that update their own object.

  5. Put validation in before, side effects in after

    Validations that should block the save call addError on Trigger.new in a before trigger. Side effects that need the record to exist (insert child records, post Chatter feed items) belong in an after trigger because the parent has an Id and is committed.

Key options
Trigger.sizeremember

Integer count of records in the batch. Useful for logging or guards that skip work when the batch is over a threshold.

Trigger.isExecutingremember

True when code is running inside a trigger. Lets a handler class share its work between trigger and non-trigger callers.

Trigger.operationTyperemember

Enum that returns the specific operation (BEFORE_INSERT, AFTER_UPDATE, etc.). Cleaner than checking pairs of boolean flags for some patterns.

Gotchas
  • Trigger.newMap is empty in before insert because the records do not have Ids yet. Code that iterates the map will silently process zero rows in before insert and admins miss the bug until production.
  • Trigger.new is read-only in after triggers. Trying to assign a field value to a record in Trigger.new from an after context throws a runtime error and rolls back the transaction.
  • Triggers fire in batches of up to 200. A bulk update of 5,000 records produces 25 separate trigger invocations, each with its own Trigger.new of up to 200. Static state used for recursion guards persists across all 25 invocations because they share a transaction.

See the full Trigger Context Variable entry

Trigger Context Variable includes the definition, worked example, deep dive, related terms, and a quiz.