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.oldMapIn 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.

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.

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.

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.

Difference Between Trigger.newMap & Trigger.oldMap in Apex
| Feature | Trigger.newMap | Trigger.oldMap |
|---|---|---|
| What it stores | Latest (new) version of records | Previous (old) version of records |
| Data type | Map<Id, SObject> | Map<Id, SObject> |
| Key | Record Id | Record Id |
| Value | Updated / Inserted record data | Old record data before update/delete |
| Used for | Accessing new values | Comparing old vs new values |
| Available in Insert | After Insert | Not Available |
| Available in Update | Before & After Update | Before & After Update |
| Available in Delete | Not Available | Before & After Delete |
| Available in Undelete | After Undelete | Not Available |
| Main Purpose | Get the latest record values quickly | Detect changes or validate updates |
| Common Use Case | Get 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:
- Trigger Helper Class in Salesforce
- Auto-Populate Fields Using Apex Trigger in Salesforce
- Create Rollup Summary on Lookup Relationship Using Salesforce Apex Trigger
- Before Insert Validation in Salesforce Trigger [With Examples]
- Restrict Record Deletion Using Salesforce Trigger

Shubham is a Certified Salesforce Developer with technical skills for Building applications using custom objects, approval processes, validation rule salesforce flows, and UI customization. He is proficient in writing Apex classes, triggers, controllers, Apex Batches, and bulk load APIs. I am also familiar with Visualforce Pages and Lighting Web Components. Read more | LinkedIn Profile