Trigger.newMap & Trigger.oldMap Context Variable in Apex Trigger

In Salesforce, Apex triggers automate processes and apply custom logic during specific database operations, such as insert, update, delete, and undelete.

In that, we use Trigger.newMap and Trigger.oldMap in Salesforce Apex, which are other types of context variables that return maps of the old versions of sObject records.

When we start learning Apex Triggers in Salesforce, everything looks simple at first. We understand:

  • What is a trigger
  • When it runs
  • How to write basic code

But then we see something like this inside the trigger. Here, confusion starts.

Trigger.newMap
Trigger.oldMap

In this article, we will learn about Trigger.newMap & Trigger.oldMap context variable in Apex trigger. In this, I will explain the following points:

  • What is this?
  • Why Map?
  • When should we use it?
  • Why not just use Trigger.new or Trigger.old?

What is Trigger.newMap in an Apex Trigger in Salesforce?

Trigger.newMap is a Map collection. In Apex Map, data is stored in key-value format.

Syntax of a Map:

Map<Key, Value>

Now in trigger:

Map<Id, SObject>

So what does this mean?

  • Key = Record Id
  • Value = Full record data

That means Trigger.newMap stores all new records using their IDs as keys.

In Salesforce triggers, the Trigger.newMap is a map of record IDs to the new versions of the records. It is available in the following events:

  • after insert
  • before update
  • after update
  • after undelete

It is NOT available in the ‘before insert‘ and ‘delete‘ events. Why?

Because before insert and delete, there is no ‘new version’ of the record. The record is being removed.

This map allows us to easily access records by their IDs, making it useful when you need to retrieve a specific record based on its unique identifier.

For example, we want to update the mailing city of the contact records whenever we update the billing city related to the account records.

What is Trigger.oldMap in an Apex Trigger in Salesforce?

Now let’s understand Trigger.oldMap. This is also a Map collection with the same syntax, having an ID and sObject.

But here it stores:

  • The old version of the records
  • Before updating or deleting

That means it contains record values before they were changed. In simple words: If you update a field, Trigger.oldMap gives you the previous value. It is available in the following events:

  • before update
  • after update
  • before delete
  • after delete

It is NOT available in the insert. Why?

Because during the insert, there is no old record. The record is new.

Why Do We Even Need a Map in an Apex Trigger?

The list and map are both used to store records, so why not just use Trigger.new Trigger.old?

Here, the problem comes. Suppose you want to compare the old and new values. You can directly use the map.

Trigger.oldMap.get(recordId)

It’s available in triggers that run before and after update, and before and after delete. You can use it to compare the old and new values of records during an update or to access deleted records by their ID in delete triggers.

This is useful for tracking changes or performing actions based on a record’s state before the current operation.

Trigger.newMap & Trigger.oldMap Context Variable in Apex Trigger

Below, I will explain the scenario and how to use Trigger.newMap & Trigger.oldMap in the apex trigger according to the condition in the trigger code.

Trigger.newMap Context Variable in Apex Trigger

For example, we want to update the mailing city of the contact records whenever we update the billing city related to the account records.

In the Apex trigger code below, I created a trigger on the account object and used the after update event because we are updating the related object’s record.

Then I created a map with ID as the key and sObject Account as the value, and assigned it to newMap.

After that, I created a list and fetched contacts using the KeySet to get them from the contact object associated with the account in Trigger.newMap.

Then, I added a loop for each contact and passed the list of contacts that we fetched to the contact object instance.

After that, create an account sObject to store the account record associated with the contact, assign the account billing city to the contact’s mailing city, and then simply update the contact list.

trigger TriggerDemo on Account(after update) {
        
    Map<Id,Account> nMap = new Map<Id,Account>();
    nMap = Trigger.newMap;
    List<Contact> cList = [ SELECT LastName, AccountId FROM Contact WHERE AccountId IN: nMap.keySet() ];
    
    for (Contact c : cList) {
        Account a = nMap.get(c.AccountId);
        c.MailingCity= a.BillingCity;
    }
    update cList;
}

Now navigate to the account records with an associated contact, update the billing city, and save the record.

Trigger.newMap &amp; Trigger.oldMap Context Variable in Apex Trigger

Here, you can see in the first image that the mailing address is null. As you update the billing address in the account, you will see that address in the mailing address.

Create Trigger in Salesforce Apex

Trigger.oldMap Context Variables in Apex Trigger

For example, if you set the opportunity amount, you don’t want another user to change it.

Even if it is editable, you can use trigger.oldMap to fetch the existing opportunity amount and check it with the new amount. If it does not match, prevent the record from being saved.

Here, we created a trigger on the opportunity object, and the event we created was a before update event.

Then I created a map with ID as the key and sObject opportunity as the value, and assigned it to oldMap.

Then, I added a loop for each trigger and passed Trigger.new, which stores the new value users will update in the amount field.

In the for loop, I created the oldOpp variable to store the records of new opportunities we fetched using the get() method.

Then, an if condition is added to check whether the new opportunity amount equals the old one.

If not, we use the addError() method to throw an error message and restrict the record from being saved.

trigger OppoTrigger on Opportunity (before update) {
    
    Map<Id, Opportunity> oppoMap = Trigger.oldMap;

        for ( Opportunity newOpp : Trigger.new ) {
        Opportunity oldOpp = oppoMap.get ( newOpp.Id );
        if ( newOpp.Amount != oldOpp.Amount ) {
            newOpp.Amount.addError ( 'Amount cannot be changed' );
        }
    }
}

As you navigate to the opportunity record, you can see the number fields with the value of 4400.

Create an Apex Trigger in Salesforce

When I changed the value and tried to save the record, the error said we passed an addError method to the record, and the record was not saved.

Apex Triggers in Salesforce

Difference Between Trigger.newMap & Trigger.oldMap in Apex

FeatureTrigger.newMapTrigger.oldMap
What it storesLatest (new) version of recordsPrevious (old) version of records
Data typeMap<Id, SObject>Map<Id, SObject>
KeyRecord IdRecord Id
ValueUpdated / Inserted record dataOld record data before update/delete
Used forAccessing new valuesComparing old vs new values
Available in InsertAfter InsertNot Available
Available in UpdateBefore & After UpdateBefore & After Update
Available in DeleteNot AvailableBefore & After Delete
Available in UndeleteAfter UndeleteNot Available
Main PurposeGet the latest record values quicklyDetect changes or validate updates
Common Use CaseGet Ids using keySet()Compare the old field value with the new value

Conclusion

I hope you have got an idea about Trigger.newMap & Trigger.oldMap context variable in Apex trigger. In this, I have explained what is a Trigger.newMap & Trigger.oldMap, when it runs, how to write basic code, and the difference between them.

You may like to read:

Agentforce in Salesforce

DOWNLOAD FREE AGENTFORCE EBOOK

Start with AgentForce in Salesforce. Create your first agent and deploy to your Salesforce Org.

Salesforce flows complete guide

FREE SALESFORCE FLOW EBOOK

Learn how to work with flows in Salesforce with 5 different real time examples.