Trigger.new vs Trigger.old — Understanding Apex Triggers the Right Way

Published: (February 6, 2026 at 10:06 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

Introduction

When learning Apex triggers, the key is understanding when to use Trigger.new versus Trigger.old.

  • Trigger.new – the data Salesforce is trying to save right now.
  • Trigger.old – the data that existed before the change.

Keeping this distinction in mind makes most usage scenarios logical.

Trigger.new

What it represents

Trigger.new contains the current or incoming values that Salesforce is attempting to insert or update.

Common use cases

  • Validations
  • Setting or modifying field values
  • Reading updated values
  • Creating related records based on new data

Available in these contexts

ScenarioAvailable?
Insert
Update
Undelete

Undelete: This trigger context runs when a record is restored from the Recycle Bin, and Trigger.new contains the record values being recovered.

Example: Validation

for (Contact con : Trigger.new) {
    if (con.Email == null) {
        con.Email.addError('Email is required');
    }
}

The validation works because Trigger.new represents the data being saved at that moment.

Trigger.old

What it represents

Trigger.old is a snapshot of the record before the change.

Common use cases

  • Detecting field changes
  • Conditional logic based on previous values
  • Preventing duplicate actions

Available in these contexts

ScenarioAvailable?
Update
Delete

Example: Detecting a change

for (Opportunity newOpp : Trigger.new) {
    Opportunity oldOpp = Trigger.oldMap.get(newOpp.Id);
    if (newOpp.StageName != oldOpp.StageName) {
        // Stage has changed
    }
}

Trigger.old provides the previous state for comparison.

Example: Detecting a meaningful update

for (Opportunity newOpp : Trigger.new) {
    Opportunity oldOpp = Trigger.oldMap.get(newOpp.Id);
    if (newOpp.StageName == 'Closed Won' &&
        oldOpp.StageName != 'Closed Won') {
        // Stage just changed to Closed Won
    }
}

Tips

  • Trigger.oldMap and Trigger.newMap give fast access to records by Id (Id → Record).
  • Using maps is preferred over looping when comparing old and new values in bulk operations.
  • Whenever your logic depends on detecting a change (not just the current value), you need both Trigger.new and Trigger.old.

Context‑Based Decision Table

RequirementUse
Validate inputTrigger.new
Modify fieldsTrigger.new
Compare old vs newTrigger.new + Trigger.old
Cleanup before deleteTrigger.old
Block record saveTrigger.new.addError()

Trigger Types

Trigger TypeWhat to Do
BeforeModify Trigger.new
AfterRead Trigger.new, compare with Trigger.old

Important: You cannot modify records using Trigger.new in after triggers because the record has already been committed to the database. At this stage, Trigger.new is read‑only. Any further changes require a separate DML operation.

Example: Updating in an after trigger using DML

List<Account> accsToUpdate = new List<Account>();
for (Account acc : Trigger.new) {
    accsToUpdate.add(new Account(
        Id = acc.Id,
        Name = 'Updated Name'
    ));
}
update accsToUpdate;

Trigger Context Overview

ContextAvailable DataPurpose
Before InsertTrigger.newRecord does not exist yet; modify fields before save
Before UpdateTrigger.new + Trigger.oldCompare old vs new; modify fields before save
After UpdateTrigger.new + Trigger.oldRecord saved; read‑only, detect changes
Before DeleteTrigger.oldRecord about to be deleted; cleanup logic
After DeleteTrigger.oldRecord deleted; read‑only, audit or related logic

Visualizing the timeline of data makes choosing the correct context natural. Instead of memorizing rules, ask:

“Am I working with new data, old data, or a change between them?”

Once answered, the appropriate context (Trigger.new, Trigger.old, or both) becomes obvious.

Best Practices

  • Bulkify your triggers – loop over collections like Trigger.new instead of single records to avoid governor limits.
  • Use Trigger.newMap and Trigger.oldMap for efficient lookups by Id instead of nested loops.
Back to Blog

Related posts

Read more »