In Salesforce, managing data between related objects is very important. Many times, we need to calculate values from child records and display them on the parent record.
For example, you may want to count the number of contacts associated with an account or calculate the total number of opportunities.
Salesforce provides a feature called a roll-up summary field to solve this problem. However, this feature works only when the objects are connected using a master-detail relationship.
When objects are connected using a lookup relationship, Salesforce does not allow creating roll-up summary fields directly.
In Salesforce, the sales team was using the sales application and wanted to display the total number of contact records related to each account directly on the account record, similar to a roll-up summary field.
But, in Salesforce, accounts and contacts have a lookup relationship, not a master-detail relationship. Salesforce does not allow creating roll-up summary fields on lookup relationships.
As a Developer, I was required to build a custom solution to calculate and display the number of contacts for each account, which functions similarly to a rollup summary field.
In this tutorial, we will learn how to create a rollup summary on a lookup relationship using Salesforce Apex Triggers. After that, whenever a contact is inserted, updated, deleted, or undeleted, the trigger automatically updates the count on the related account.
What is a Roll-Up Summary Field in Salesforce?
A roll-up summary field is used to calculate values from related child records and display the result on the parent record. These calculations can include:
- Count of records
- Sum of values
- Minimum value
- Maximum value
For example:
- Count total contacts on an account
- Sum of opportunity amounts
- Maximum order value
This feature is very powerful because it automatically updates values when data changes.
Can We Create a Rollup Summary Field on a Lookup Relationship Object in Salesforce?
No, there is no direct way to create a Salesforce rollup summary field on a lookup relationship; it can only be created on a master-detail relationship.
To achieve a similar functionality with a lookup, we must use an Apex trigger, Salesforce Flow, or a third-party AppExchange application, such as a rollup helper or declarative lookup rollup summaries (DLRS).
In the steps below, I will demonstrate what happens when we try to create a rollup summary field on an object with a lookup relationship.
Here, I will create a custom roll-up summary field on the account object that displays the total number of contact records associated with that account.
For that, go to the Gear Icon. -> Click on the Setup. -> Select the Object Manager tab. Select the Object on which you want to create the Rollup Summary Field. Here, I’m going to create an Account Object.
In the account setup, click Fields and Relationships, then click the New button to create a new field.
In this step, since we want to display the count of contacts related to an account object, we will select the Rollup Summary option from the data type and click Next.

Next, provide the Field Label and API Name for the rollup summary field, then click Next.

Next, we would normally select the Summarized Object from which we want to summarize the data. In our case, the object would be Contact, since we want to count the number of Contacts associated with an Account.
However, because Account and Contact are in a Lookup relationship (not a Master-Detail relationship), the contact object does not appear in the list of available summarized objects when creating a rollup summary field.

Create Rollup Summary on Lookup Relationship Using Salesforce Apex Trigger
Since we cannot create a standard rollup summary field on a lookup relationship directly, we will write an Apex Trigger on the Contact object and implement the business logic into a Helper Class.
The first step is to create a custom Number field on the Account object to display the total number of related Contacts. Let’s name this field Total_Contacts__c.
This field will function as a roll-up summary field, but instead of being automatically updated by Salesforce, it will be updated by our Apex Trigger logic whenever any Contact record is inserted, updated, deleted, or undeleted.

First, we will create a Helper Class to implement the logic that calculates the number of Contact records related to an Account and updates the custom field (Total_Contacts__c) on the Account record.
To create the class, go to Setup → Developer Console -> File -> New -> Apex Classes → and then write the Apex class with the required logic.
In the method, I declared a List collection that retrieves the contact records from the trigger, and then we use this List to store both new and old contact records.
After that, we use a for loop to iterate over the Account records stored in the list. To get only unique records, we store them in a Set.
Then, using a Map collection, we mapped the Account Name to the corresponding Account record in Salesforce, which we retrieved using a SOQL query. That means we are creating a key-value pair.
Next, using the COUNT() operator in a SOQL query, we will calculate the total number of Contact records per Account.
After fetching this count, we will update the custom Number field (Total_Contacts__c) on the Account object to always display the correct number of related Contacts.
public class ContactTriggerHandler {
public static void updateContactCount(List<Contact> newList, List<Contact> oldList, Boolean isDelete) {
//Declare the variable first
Set<Id> accountIds = new Set<Id>();
// Collect Account Ids from new records
if(newList != null){
for(Contact con : newList){
if(con.AccountId != null){
accountIds.add(con.AccountId);
}
}
}
// Collect Account Ids from old records (for deletes/updates)
if(oldList != null){
for(Contact con : oldList){
if(con.AccountId != null){
accountIds.add(con.AccountId);
}
}
}
if(accountIds.isEmpty()){
return; // nothing to process
}
// Count Contacts for each Account
Map<Id, Integer> accountContactCount = new Map<Id, Integer>();
for(AggregateResult ar : [
SELECT AccountId, COUNT(Id) totalContacts
FROM Contact
WHERE AccountId IN :accountIds
GROUP BY AccountId
]){
accountContactCount.put((Id)ar.get('AccountId'), (Integer)ar.get('totalContacts'));
}
// Update Account with Contact count
List<Account> accountsToUpdate = new List<Account>();
for(Id accId : accountIds){
Account acc = new Account(Id = accId);
acc.Total_Contacts__c = accountContactCount.containsKey(accId) ? accountContactCount.get(accId) : 0;
accountsToUpdate.add(acc);
}
if(!accountsToUpdate.isEmpty()){
update accountsToUpdate;
}
}
}
In the trigger below, we have defined the object on which the trigger is created and the trigger events that will fire the logic. Here, the trigger is defined on the Contact object and runs after insert, update, delete, and undelete.
These events are required because any of these operations can change the number of contacts associated with an account, and we want the count on the Account to stay up to date.
Then, using the helper class name, call the methods in the order you want to execute.
trigger ContactTriggers on Contact (after insert, after update, after delete,
after undelete) {
if(Trigger.isAfter){
if(Trigger.isInsert || Trigger.isUpdate || Trigger.isDelete || Trigger.isUndelete){
ContactTriggerHandler.updateContactCount(Trigger.new, Trigger.old,
Trigger.isDelete);
}
}
}
Proof of concept:
In the screenshot below, you can see in the Related tab of the Account record, under the contacts section, four existing Contact records are related to the Agro Tech Account.

As you open the Detail tab, the custom field Total_Contacts__c on the account displays a value of 4, because our trigger has automatically counted the related contacts and updated the field.

In this way, we can create a rollup summary on a lookup relationship using Salesforce Apex Trigger.
Frequently Asked Questions
Q1: Can we create a roll-up summary on the lookup?
No, not directly
Q2: What is the best method?
1. Apex for developers
2. DLRS for admins
Q3: Is Flow good for roll-up?
Yes, for simple use cases
Conclusion
Roll-up summary fields are very useful in Salesforce, but they work only with master-detail relationships. When working with lookup relationships, we need to use alternative approaches such as Apex triggers, Flow, or DLRs.
Among these methods, Apex provides the most flexibility, while Flow and DLRS provide easier solutions for admins. By understanding these approaches, you can implement roll-up logic in any real-time Salesforce project.
You may like to read:
- Before Insert Validation in Salesforce Trigger [With Examples]
- Restrict Record Deletion Using Salesforce Trigger
- Before vs After Triggers in Salesforce: When to Use & Why

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