DEV Community

Rubasri Srikanthan
Rubasri Srikanthan

Posted on

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

When I first started learning Apex triggers, I wasn’t always sure when to use Trigger.new versus Trigger.old.

By focusing on how they actually work, I was able to grasp it clearly and apply it effectively.


Core Idea

Trigger.new → the data Salesforce is trying to save right now.

Trigger.old → the data that existed before the change.

Keeping this in mind, most usage scenarios become logical.


1. When to Use 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:

Scenario Available?
Insert Yes
Update Yes
Undelete Yes

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');
    }
}
Enter fullscreen mode Exit fullscreen mode

This works because Trigger.new represents the data being saved right now.


2. When to Use 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:

Scenario Available?
Update Yes
Delete Yes

Example: Detecting a change

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

Trigger.old is useful because it gives you the previous state of the record for comparison.

Tip: Trigger.oldMap and Trigger.newMap provide fast access to records by Id (Id → Record). Using maps is preferred over looping when comparing old and new values in bulk operations.


3. Using Trigger.new and Trigger.old Together

Whenever your logic depends on detecting a change, not just the current value, you need both.

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
    }
}
Enter fullscreen mode Exit fullscreen mode

Using both helps prevent:

  • Duplicate execution

  • Logic running on unrelated updates

  • Incorrect automation


4. Context-Based Decision Table

Requirement Use
Validate input Trigger.new
Modify fields Trigger.new
Compare old vs new Trigger.new + Trigger.old
Cleanup before delete Trigger.old
Block record save Trigger.new.addError()

5. Before vs After Triggers

Trigger Type What to Do
Before Modify Trigger.new
After Read 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, Salesforce marks Trigger.new as read-only to preserve data integrity. Any further changes require a separate DML operation.

Example : Updating in 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;
Enter fullscreen mode Exit fullscreen mode

6. Trigger Timeline

Think about triggers in terms of whether a record already exists and what Salesforce is doing with it.

Trigger Context Available Data Purpose
Before Insert Trigger.new Record does not exist yet, modify fields before save
Before Update Trigger.new + Trigger.old Compare old vs new, modify fields before save
After Update Trigger.new + Trigger.old Record saved, read-only, detect changes
Before Delete Trigger.old Record about to be deleted, cleanup logic
After Delete Trigger.old Record deleted, read-only, audit or related logic

Visualizing the timeline of data makes using the correct context natural.


Final Thought

Instead of memorizing rules, I always ask:

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

Once you answer that, the correct context (Trigger.new, Trigger.old, or both) becomes obvious.


Pro Tips

  • Always 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.


About Me

I’m a curious Salesforce Developer who enjoys breaking down complex concepts into simple, practical explanations.

Top comments (0)