Close Menu
SalesforceCodex
    Facebook X (Twitter) Instagram
    Trending
    • Top 10 Salesforce Flow Features of Salesforce Summer ’25
    • Unlock the Power of Vibe Coding in Salesforce
    • How to Implement Dynamic Queueable Chaining in Salesforce Apex
    • How to Implement Basic Queueable Chaining in Salesforce Apex
    • How to Suppress PMD Warnings in Salesforce Apex
    • Top 10 PMD Issues Salesforce Developers Should Focus on in Apex
    • How to Use Graph API for Outlook-Salesforce Connection
    • Enhancing Performance with File Compression in Apex
    Facebook X (Twitter) Instagram
    SalesforceCodex
    Subscribe
    Tuesday, May 20
    • Home
    • Architecture
    • Salesforce
      • News
      • Apex
      • Integration
      • Books Testimonial
    • Questions
    • Certification
      • How to Prepare for Salesforce Integration Architect Exam
      • Certification Coupons
    • Integration Posts
    • Downloads
    • About Us
      • Privacy Policy
    SalesforceCodex
    Home»Salesforce»Apex»Apex Trigger Code Optimization

    Apex Trigger Code Optimization

    Dhanik Lal SahniBy Dhanik Lal SahniMarch 30, 2022Updated:June 11, 20232 Comments8 Mins Read
    Facebook Twitter Pinterest LinkedIn Tumblr Email
    Apex Trigger Code Optimization
    Share
    Facebook Twitter LinkedIn Pinterest Email

    Apex triggers enable us to perform some custom actions before or after changes to Salesforce records. These changes can be record insertions, updates, or deletions. As these are firing before or after any record changes, it will affect performance, if the trigger code is not optimized. This post will provide different ways to Apex Trigger Code Optimization.

    Let us see problems and solutions which we can implement in Apex Trigger to solve the performance issue.

    1. Avoid SOQL In Loop

    This is a common issue that I have found while reviewing the code of many developers. Developer fetches query in the loop considering their current use case. They think that we need to perform some action for record change which will be performed on UI.

    trigger InsuranceFormTrigger on InsuranceForm__c (before insert, before update) {
    	for(InsuranceForm__c m : Trigger.new){ 
    	   	Account a = [SELECT Id FROM Account WHERE Name= m.AccountId__c];
    		//Some code Action here
    	}
    }

    This is a very simple use case, where the developer is trying to get Account information for the current InsuranceForm record. If we see this code, it looks good but what if we have to upload multiple records using a data loader or any other tool. Will that code work..? Absolutely not, as the query will be fetched in the loop and it will throw an error just after 200 records.

    Optimized Code :

    We have to take SOQL out from the loop and collect all required IDs in the loop first and then we should use SOQL.

    trigger InsuranceFormTrigger on InsuranceForm__c (before insert, before update) {
    	
    	Set<Id> accountIds=new Set<Id>();
    
    	//Collect AccountIds first
    	for(InsuranceForm__c m : Trigger.new){ 
    		//Avoid nulls
    		if(string.isNotBlank(m.AccountId__c))
    		{
    			accountIds.add(m.AccountId__c); 
    		}
    	}
    
    	//Ids exist then proceed further
    	if(!accountIds.isEmpty())
    	{
    		Account a = [SELECT Id FROM Account WHERE Id=:accountIds];
    		//Some Action here
    	}
    }

    We should always avoid nulls in the query filter so add code to put Ids in Set only when it has value.

    2. Avoid Loop to get changed Records

    Many developers use for loop to just identify record Ids that are changed or newly inserted like the below code.

    trigger InsuranceFormTrigger on InsuranceForm__c (after insert, after update) {
    {
    	Set<Id> newRecords=new Set<Id>();
    	for(InsuranceForm__c m : Trigger.new){ 
    		newRecords.add(m.Id); 
    	}
    }

    It is not required as there is already a global trigger variable (Trigger.newMap) to provide a newly inserted/updated sObject. The above trigger code can easily be changed like below.

    trigger InsuranceFormTrigger on InsuranceForm__c (after insert, after update) {
    {
    	Set<ID> ids = Trigger.newMap.keySet();
    	//Trigger.newMap is Map of Id and sObject. Use ids in some action or other query
    }

    3. Avoid Hardcoded Id

    While writing code sometimes we use hardcoded id like record type id, profile id, or permission set id to test functionality. We forget to change it and this hardcode id gives undesirable output while running our application in another org.

    It will throw an error also when we were moving our code to a different org and the test class will validate. Those hardcode IDs will not be available in the test context of another org, so we will get errors.

    for(Case c: Trigger.new){
       if(c.RecordTypeId=='0124000000095uy'){ // Lead Case
          // ...
       } else if(c.RecordTypeId=='0126000000095Gmwer'){ // Support Case
          // ...
       }
    }

    In the above code sample, RecordTypeId – 0124000000095uy and 0126000000095Gm are hardcoded and this code will only work in the current org. This code will throw an error when we create a test class or when we move this to another org.

    Optimized Code:

    Instead of using a hardcoded id, we can utilize a record type name to retrieve the record type id in the current org. So above code can be written like below

    //Case Record Type Id based on Record Type Name
    Id leadCaseTypeId= Schema.SObjectType.Case.getRecordTypeInfosByName().get('Lead Case').getRecordTypeId();
    Id supportCaseTypeId= Schema.SObjectType.Case.getRecordTypeInfosByName().get('Support Case').getRecordTypeId();
    
    for(Case c: Trigger.new){
       if(c.RecordTypeId==leadCaseTypeId){ // Lead Case
          // ...
       } else if(c.RecordTypeId==supportCaseTypeId){ // Support Case
          // ...
       }
    }

    If your application code is using other then RecordTypeID hardcoded id, then you can utilize Custom Setting, Custom Metadata Type, or Custom Label as well to make that code dynamic.

    4. Avoid Recursive Call

    Many times we are creating triggers to update the same record after some processing. This can create a recursive trigger call and the system will throw Maximum trigger depth exceeded , if we have not implemented the code properly.

    Let us take an example, When a new file is uploaded to Account record, we will create a Case to approve this file. This record will go under the approval process. When the case is approved, we will close the case and update a few other details in the case and account record.

    In the above case as soon as the Case is approved, we have to close this case and update the fields. We have to use trigger here to run code as soon as the case is approved.

    trigger CaseTrigger on Case (after update) {
    {
    	List<Case> cases=new List<Case>();
    	for(Case c: Trigger.new){
    		if(c.Stage__c=='Approved')
    		{
    			c.Status='Closed';
    		}
    		cases.add(c);
    		//Adding case in list in all situation 
    	}
    	update cases;
    }

    In the above code, we are checking Case.Stage__c field and updating Status field as well but we are adding current iterative case in the list (cases.add(c)) every time. So when the update will fire, the same record will update and it will execute this trigger code block once again and this will keep calling the same code.

    Optimized Code:

    trigger CaseTrigger on Case (after update) {
    {
    	List<Case> cases=new List<Case>();
    	for(Case c: Trigger.new){
    		//Status will only updated when it is not Closed
    		//So after Case is updated and same code is execute then this block condition will not met
    		//and not executed again
    		if(c.Stage__c=='Approved' && c.Status!='Closed')
    		{
    			c.Status='Closed';
    			cases.add(c);
    			//Adding case in list
    		}
    	}
    	if(!cases.isEmpty())
    	{
    		update cases;
    	}
    }

    Similar to this there can be any situation where you are updating the same record and it is firing the update record statement again and again for the same record. Put some conditions so that it will not do a recursive call. In the above example, I have used c.Status!=’Closed’ to restrict record update. There is another solution outlined at Apex Trigger Best practices to avoid recursion for recursive trigger issues.

    5. Use One trigger per object

    Many times developer asks, I have created 2 or n triggers on the same object, which trigger will fire first? And we can not give an exact answer to this question as we can not determine the trigger execution order. This question is asked by developers to verify their code will be executed in which order. The solution for this question is to create one trigger per object and put your code in proper order. So that your code will be executed as per your requirement.

    How to make one trigger per object?

    In trigger, we can write code related to record insert, update, delete, undelete, upsert or merge-operations. We can perform an action before and after these operations.

    So we have to create a separate trigger handler class and add separate methods for each action and record operation. So take an example for account object we have to write trigger like this.

    trigger AccountTrigger on Account (
        before insert, after insert, 
        before update, after update, 
        before delete, after delete,
        after undelete
    ) {
        
        if (Trigger.isBefore) {
            if (Trigger.isInsert) {
                // Call Trigger handler class method for before insert operation
            } 
            if (Trigger.isUpdate) {
                // Call Trigger handler class method for before update operation
            }
            if (Trigger.isDelete) {
                // Call Trigger handler class method for before delete operation
            }
        }
        
        if (Trigger.isAfter) {
            if (Trigger.isInsert) {
                // Call Trigger handler class method for after insert operation
            } 
            if (Trigger.isUpdate) {
                // Call Trigger handler class method for after update operation
            }
            if (Trigger.isDelete) {
                 // Call Trigger handler class method for after delete operation
            }
            
            // Not supported for all objects
            if (Trigger.isundelete) {
                 // Call Trigger handler class method for after undelete operation
            }
        }
    }

    As per the above code, for each action, we have to create a separate trigger handler method. If you don’t have a use case for any action then delete that code block. For example, if no custom action is required on delete then remove Trigger.isDelete code block from code. Let us create a trigger handler class and update the trigger.

    flagPractionerVerification is called before insert opertaion and closeAllTasks method is called after insert operation. If we want to add other methods or code blocks after or before these methods, we can easily add those methods. This way we can create order execution.

    Similar to flagPractionerVerification and closeAllTasks other methods can be created in the handler class and called from a specific record trigger operation.

    Benefits of this pattern:

    1. Can control order execution of code
    2. Cleaner Code
    3. Easy to create a test class
    4. Maintainable code

    References:

    Trigger Syntax

    Are there ever exceptions to the one trigger per object rule?

    Related Articles:

    Optimize SOQL Filter in Apex Code

    Optimize Apex Code by Metadata Caching

    Optimize Code by Disabling Debug Mode

    Optimizing Loop in Apex Code

    apex apex code best practice apex trigger best practices best practices in salesforce code review points hardcoded ids in code one trigger per object optimize apex code optimize apex trigger optimize trigger salesforce best practice
    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    Previous ArticleSalesforce DropBox Integration to upload files
    Next Article AWS Signature 4 Signing in Salesforce
    Dhanik Lal Sahni
    • Website
    • Facebook
    • X (Twitter)

    With over 18 years of experience in web-based application development, I specialize in Salesforce technology and its ecosystem. My journey has equipped me with expertise in a diverse range of technologies including .NET, .NET Core, MS Dynamics CRM, Azure, Oracle, and SQL Server. I am dedicated to staying at the forefront of technological advancements and continuously researching new developments in the Salesforce realm. My focus remains on leveraging technology to create innovative solutions that drive business success.

    Related Posts

    By Dhanik Lal Sahni6 Mins Read

    Top 10 Salesforce Flow Features of Salesforce Summer ’25

    May 11, 2025
    By Dhanik Lal Sahni6 Mins Read

    Unlock the Power of Vibe Coding in Salesforce

    April 30, 2025
    By Dhanik Lal Sahni5 Mins Read

    How to Implement Dynamic Queueable Chaining in Salesforce Apex

    April 21, 2025
    View 2 Comments

    2 Comments

    1. Pingback: Optimizing Salesforce Apex Code | SalesforceCodex

    2. Pingback: Correctly Publish Platform Event with Salesforce Apex

    Leave A Reply Cancel Reply

    Ranked #1 SALESFORCE DEVELOPER BLOG BY SALESFORCEBEN.COM
    Featured on Top Salesforce Developer Blog By ApexHours
    Recent Posts
    • Top 10 Salesforce Flow Features of Salesforce Summer ’25
    • Unlock the Power of Vibe Coding in Salesforce
    • How to Implement Dynamic Queueable Chaining in Salesforce Apex
    • How to Implement Basic Queueable Chaining in Salesforce Apex
    • How to Suppress PMD Warnings in Salesforce Apex
    Ranked in Top Salesforce Blog by feedspot.com
    RSS Recent Stories
    • How to Connect Excel to Salesforce to Manage Your Data and Metadata February 9, 2025
    • Difference Between With Security and Without Security in Apex January 2, 2025
    • Top Reasons to Love Salesforce Trailhead: A Comprehensive Guide December 5, 2024
    • How to Utilize Apex Properties in Salesforce November 3, 2024
    • How to Choose Between SOQL and SOSL Queries July 31, 2024
    Archives
    Categories
    Tags
    apex (110) apex code best practice (8) apex rest (11) apex trigger best practices (4) architecture (22) Asynchronous apex (9) AWS (5) batch apex (9) batch processing (4) code optimization (8) code review tools (3) custom metadata types (5) design principle (9) einstein (3) flow (15) future method (4) google (6) google api (4) integration (19) integration architecture (6) lighting (8) lightning (64) lightning-combobox (5) lightning-datatable (10) lightning component (29) Lightning web component (61) lwc (50) named credential (8) news (4) optimize apex (3) optimize apex code (4) Permission set (4) Queueable (9) rest api (23) S3 Server (4) salesforce (140) salesforce apex (46) salesforce api (4) salesforce api integration (5) Salesforce Interview Question (4) salesforce news (5) salesforce question (5) solid (6) tooling api (5) Winter 20 (8)

    Get our newsletter

    Want the latest from our blog straight to your inbox? Chucks us your detail and get mail when new post is published.
    * indicates required

    Ranked #1 SALESFORCE DEVELOPER BLOG BY SALESFORCEBEN.COM
    Featured on Top Salesforce Developer Blog By ApexHours
    Recent Posts
    • Top 10 Salesforce Flow Features of Salesforce Summer ’25
    • Unlock the Power of Vibe Coding in Salesforce
    • How to Implement Dynamic Queueable Chaining in Salesforce Apex
    • How to Implement Basic Queueable Chaining in Salesforce Apex
    • How to Suppress PMD Warnings in Salesforce Apex
    Ranked in Top Salesforce Blog by feedspot.com
    RSS Recent Stories
    • How to Connect Excel to Salesforce to Manage Your Data and Metadata February 9, 2025
    • Difference Between With Security and Without Security in Apex January 2, 2025
    • Top Reasons to Love Salesforce Trailhead: A Comprehensive Guide December 5, 2024
    • How to Utilize Apex Properties in Salesforce November 3, 2024
    • How to Choose Between SOQL and SOSL Queries July 31, 2024
    Archives
    Categories
    Tags
    apex (110) apex code best practice (8) apex rest (11) apex trigger best practices (4) architecture (22) Asynchronous apex (9) AWS (5) batch apex (9) batch processing (4) code optimization (8) code review tools (3) custom metadata types (5) design principle (9) einstein (3) flow (15) future method (4) google (6) google api (4) integration (19) integration architecture (6) lighting (8) lightning (64) lightning-combobox (5) lightning-datatable (10) lightning component (29) Lightning web component (61) lwc (50) named credential (8) news (4) optimize apex (3) optimize apex code (4) Permission set (4) Queueable (9) rest api (23) S3 Server (4) salesforce (140) salesforce apex (46) salesforce api (4) salesforce api integration (5) Salesforce Interview Question (4) salesforce news (5) salesforce question (5) solid (6) tooling api (5) Winter 20 (8)

    Get our newsletter

    Want the latest from our blog straight to your inbox? Chucks us your detail and get mail when new post is published.
    * indicates required

    Facebook X (Twitter) Instagram Pinterest YouTube Tumblr LinkedIn Reddit Telegram
    © 2025 SalesforceCodex.com. Designed by Vagmine Cloud Solution.

    Type above and press Enter to search. Press Esc to cancel.

    Ad Blocker Enabled!
    Ad Blocker Enabled!
    Our website is made possible by displaying online advertisements to our visitors. Please support us by disabling your Ad Blocker.