Introduction
Salesforce operates on a multi-tenant architecture, where resources like memory, database, and processing power are shared across multiple organizations.
To ensure fairness and avoid system overload, Salesforce enforces governor limits.
These limits are very much essential for platform stability but can pose challenges for developers working with large data sets or complex logic.
In this blog, we will explore some best practices to ensure that your code stays within these governor limits, ensuring efficient and scalable Salesforce applications.
If you’re unfamiliar with Governor Limits in Salesforce, I recommend checking out the post linked below before proceeding with this one.
Now, lets start with some best practises developers should follow to stay within Governor Limits in Salesforce.
1. Bulkify your code
One of the most important principle in Salesforce development is – Bulkifying your code.
Bulkification ensures that your code can handle multiple records at once, rather than processing single record at a time.
This helps you stay within the limits on SOQL queries, DML statements and other resources.
Example of Non-Bulkified code
for (Account acc : Trigger.new) {
Account existingAcc = [SELECT Id FROM Account WHERE Name = :acc.Name];
update existingAcc;
}
Example of Bulkified code
List accNames = new List();
for (Account acc : Trigger.new) {
accNames.add(acc.Name);
}
List existingAccs = [SELECT Id, Name FROM Account WHERE Name IN :accNames];
for (Account existingAcc : existingAccs) {
// Process bulk records
}
Why Bulkification Matters?
Processing the records in bulk reduces the number of SOQL queries and DML operation, which helps you stay within Salesforce governor limits.
2. Avoid SOQL and DML inside FOR Loop.
This is a common mistake developers make – is that they write SOQL statements and perform DML operation inside FOR Loop, which can cause your transaction to fail.
Example of Inefficient Code
for (Account acc : accountsList) {
Account existingAcc = [SELECT Id FROM Account WHERE Name = :acc.Name];
update existingAcc;
}
As we know, Salesforce enforces a Governor Limit of 100 SOQL queries per synchronous transaction. This means a maximum of 100 SOQL queries can be executed within a single transaction.
However, if you look at the example above, there is a SOQL query being executed for every record inside the loop. This approach can lead to exceeding the 100 SOQL queries limit per transaction.
Example of Efficient Code
List accNames = new List();
for (Account acc : accountsList) {
accNames.add(acc.Name);
}
List existingAccs = [SELECT Id, Name FROM Account WHERE Name IN :accNames];
List accountsToUpdate = new List();
for (Account existingAcc : existingAccs) {
// Add to the list of accounts to update
accountsToUpdate.add (existingAcc);
}
update accountsToUpdate;
Why this matters?
By moving SOQL and DML operation outside of FOR LOOP, we reduce the number of SOQL queries and DML operation executed, which helps to stay within Governor Limits.
3. Use SOQL 'For Loops' for Large Datasets
When dealing with large datasets, use SOQL For Loops to process records in the chunk of 200, which helps avoid heap size limit.
for (List accList : [SELECT Id, Name FROM Account]) {
// Process accounts in chunks of 200
}
Why this matters?
This approach reduces memory consumption by fetching records in manageable chunks, helping to stay within the 6MB heap size limit for synchronous transaction.
4. Use Efficient SOQL Queries
Efficient use of SOQL queries is also important as it helps to reduce resource consumption.
Developers should only query the fields and records that is needed.
Always avoid use unselective filters that can result in retrieving more data than required.
Example of Inefficient Query
List accounts = [SELECT Id, Name, Industry, Phone FROM Account];
Example of Efficient Query
List accounts = [SELECT Id, Name FROM Account WHERE Industry = 'Technology'];
Why this matters?
Selective query ensures that developers only retrieve the required data which reduces the risk of hitting limits on the number of records retrieved.
4. Use Asynchronous Processing
Asynchronous apex (such as @future method, Batch apex and Queuable apex) allows developers to perform operations outside the context of current transaction.
This helps to bypass many governor limits like – CPU time limit, heap size etc.
Example of using Asynchronous Apex - @future method
@future
public static void updateAccounts (List accountsToUpdate) {
update accountsToUpdate;
}
Example of Batch Apex - for processing large set of data
public class AccountBatch implements Database.Batchable {
public Database.QueryLocator start (Database.BatchableContext bc) {
return Database.getQueryLocator ('SELECT Id, Name FROM Account');
}
public void execute (Database.BatchableContext bc, List scope) {
// Process each batch of records
for (Account acc : scope) {
// Logic here
}
}
public void finish (Database.BatchableContext bc) {
// Final logic here
}
}
Why this matters?
This is important because – when you move heavy operations to asynchronous processing, it helps you to avoid governor limits in synchronous transaction.
This is because – asynchronous apex has higher limits for CPU time, heap size and other resources.
For example: In asynchronous transaction, the governor limit of CPU time increases to 60,000 milliseconds, compared to 10,000 milliseconds in synchronous Apex
If you’re unfamiliar with Asynchronous Apex in Salesforce, such as Future Method, Batch Apex or Queueable Apex, I recommend checking out the post linked below before proceeding with this one.
5. Use Collections for DML Operations
Developers should always use collections like – Lists or Sets to handle multiple records at once while performing DML operations (such as Insert, Update or Delete) or querying records in Salesforce.
Example of incorrect code:
Below code inserts 4 accounts in a single transaction, which has 4 DML statements.
This is not correct way of performing DML operation – because if there is a requirement to insert 200 Accounts, then there will be 200 DML statements and eventually this transaction will fail as Salesforce allows only 150 DML operations in a single transaction
insert account1;
insert account2;
insert account3;
insert account4;
Corrected Code:
Instead of writing the above code, we can insert the same 4 Accounts with the help of a single DML statement.
List accounts = new List{account1, account2, account3, account4};
insert accounts;
Why this matters?
By performing DML operation on multiple records at once, you reduce the number of DML statements and stay within the governor limit of 150 DML statements per transaction.
6. Use Collections to reduce SOQL Queries
When working with multiple records, developers should always use collections (like Lists or Sets) in their SOQL queries to retrieve or update data in bulk.
This ensures that – number of SOQL queries are minimised in a transaction.
For Example:
Set accountIds = new Set();
for (Opportunity opp : Trigger.new) {
accountIds.add (opp.AccountId);
}
List accounts = [SELECT Id, Name FROM Account WHERE Id IN :accountIds];
Why this matters?
By retrieving multiple records at once, a developer can reduce the number of queries and stay within the governor limit of 100 SOQL queries per transaction.
7. Limit the use of recursive triggers
Triggers that update records and cause other triggers to fire can cause recursion, which may result in exceeding Governor Limits.
To avoid this, implement logic to stop recursion in trigger.
if (!Trigger.isExecuting && !recursionFlag) {
recursionFlag = true;
// Your logic here
}
Why this matters?
By preventing recursion, developers avoid hitting limits on SOQL query, DML operation and CPU time.
If you’re not familiar with recursion in Salesforce Triggers, I highly recommend exploring the post linked below. Understanding this concept is crucial, as it is a commonly asked interview question.
Conclusion
Salesforce governor limits ensure that the platform remains scalable and efficient for all users, but they can be restrictive if not handled properly.
By following best practices like bulkifying your code, using asynchronous processing, and writing efficient SOQL queries, you can stay well within governor limits and build more scalable, efficient applications.
Always test your code with larger data volumes to ensure that it scales properly under governor limits, and leverage Salesforce tools like Apex Governor Limit Monitoring to track resource consumption.