Developers / Admins

What Are Salesforce Governor Limits? Best Practices & Examples

By Andy Hitchings

The Salesforce Governor Limits concept exists because Salesforce and Apex run in a multitenant environment. Multitenancy is a fundamental technology that sits alongside cloud computing.

Back when on-premise servers ruled the earth, you would purchase one or many servers to sit within your office or home. These servers would run your applications, and you would own the full processing power and storage capacity. You would also be responsible for the upkeep, maintenance, and upgrades. Fast forward to today, and multitenancy allows us to share resources with other users of an application, in a cost-effective and secure manner.

What Is Salesforce Multitenancy?

Due to the nature of multitenancy and the fact we are sharing resources, governor limits are in place to ensure that any Apex we develop does not monopolize the shared resources we are allocated.

Imagine this: there are 100 flats in a single apartment building. The 100 flats share resources: water, electricity, gas, and wi-fi bandwidth. Imagine if several flats started some Bitcoin mining which started to hog all of the electricity. Then imagine if some other flats started to download huge 4k video files from the interwebs. And then also imagine if some other flats were running baths all at the same time. If you lived in this apartment building, things would turn into a nightmare – you wouldn’t be able to stream any videos online in any reasonable time frame, your electricity bills would quadruple in a single month, and the water pressure in your shower would decline to an embarrassing trickle.

The apartment building is a Salesforce instance (also known as a pod or server). The flats are the individual Salesforce orgs (there can be tens of thousands of orgs on a single server). The distribution of shared resources is the multitenancy architecture.

This analogy helps to explain why governor limits are so helpful – they prevent inconsiderate actors from hogging database, memory, network, or processor resources that you and other customers on the same server need to effectively run their business processes in the cloud. So, governor limits dictate what your code can and cannot do when it is executed on the Salesforce platform. This contributes to the scalability of the platform since the resource allocation is defined.

What Are Salesforce Governor Limits?

There are many different types of governor limits, some of which are tied to your Salesforce edition. For example, Professional Edition enables one to have 50 custom objects, but 2,000 for Unlimited and Performance.

Some other governor limits have ‘soft’ limits that can either be solved by Salesforce or by purchasing additional add-ons. For example, the current limit is 6MB of Apex code per org, but this can be increased on a case-by-case basis by Salesforce Support. Other limits are based on a combination of both your Salesforce edition and the number of user licenses on the org – for example, API and data storage limits.

Other governor limits are associated more with programming in Apex: for example, an Apex class/execute anon script can only have 100 SELECT statements per synchronous transaction. Some of these limits are ‘hard’, meaning that they cannot be increased, and so a new approach by the developer would be needed to achieve the desired result.

This Trailhead module on multitenancy goes into more detail on this subject.

Types of Salesforce Governor Limits

  • Per Transaction Apex Limits: These limits count for each Apex transaction. For Batch Apex, these limits are reset for each execution of a batch of records in the execute method.
  • Per Transaction Certified Managed Package Limits: If a managed package developed by a Salesforce ISV has passed security review, they are provided with generally higher per-transaction limits.
  • Lightning Platform Apex Limit: These limits aren’t specific to an Apex Transaction and are enforced by the Lightning platform.
  • Static Apex Limit: Apex limits that are applied across all transactions.
  • Size-Specific Apex Limit: Apex limits related to the size of code.
  • Miscellaneous Apex Limit: Other limits.

Why Are Salesforce Governor Limits Important?

Governor limits are a concept that all Salesforce Developers (and admins to a lesser extent), must grasp. They will fundamentally shape the way that you architect Salesforce solutions, as well as how the code is written.

If a Salesforce governor limit is hit, the associated governor issues a runtime exception that cannot be handled, which translates to: your code breaks and won’t work.

Governor Limit Best Practices

As per the official docs, there are a huge number of different types of governor limits. This article will cover some of the more common ones associated with Apex programming, and outline approaches that can be taken to resolve them.

1. SOQL 100 Limit – Exercise 1

One of the most well known governor limits is that an apex class/execute anonymous script can ‘only’ have 100 SELECT statements per Apex Transaction.

By the way, an Apex Transaction is a set of operations that are executed in a single unit. For example, when a trigger runs on every account that has its name updated, processing is done to update all references across tasks and events from the old account name to the new account name. The sum of operations and resources that are leveraged that take place to achieve this is the Apex Transaction.

To demo this particular governor limit, go to a Sandbox and navigate to the Developer Console. Either input cmd + E or Debug | Open Execute Anonymous Window and input the ‘Exercise 1’ code in the Gist at the end of this post. 

for (integer i = 0; i <= 100; i++)
{
    Integer countOfAccounts = [SELECT COUNT() FROM Account];
}

Upon highlighting and then selecting “Execute Highlighted” in the Dev console, you’ll receive the following error:

This is happening as per the docs; you can only have 100 SELECT statements in a synchronous context.

 

Governor Limit Fix

Oftentimes, this governor limit will be hit because there is a SOQL statement in a for loop, which is considered one of the ‘cardinal sins’ of programming in Apex.

List<Account> accounts = [SELECT Id, Name FROM Account];
List<Integer> contactCount = new List<Integer>();
for (Integer i = 0; i <= accounts.size(); i++)
{
   Integer count = [SELECT COUNT() FROM Contact WHERE AccountId IN : accounts ];
   contactCount.add(count);
}

The moment there are more than 99 accounts in the variable ‘accountList’, the code will fail.

A simple solution is simply to move all SOQL statements outside of for loops, and especially if the for loop iterator is dynamic (the number of accounts in the list could change but if the iterator is a number, then that is fixed). To do that, you’ll likely be depending more on other collections and inventive SOQLs.

An approach can be like so:

Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id FROM Account]);
Map<String, Integer> accountNamesAndRespectiveContactCounts = new Map<String, Integer>();
for(Account accountObject : [SELECT Name, (SELECT Id FROM Contacts) FROM Account WHERE Id IN :accountMap.keySet()]) 
{    
accountNamesAndRespectiveContactCounts.put(accountObject.Name,     accountObject.Contacts.size()); 
}
system.debug('accountObject map is: ' + accountNamesAndRespectiveContactCounts);

2. DML 150 Limit

Probably the second most well-known governor limit concerns the number of DML operations in a single transaction. As per the docs, the limit is 150:

To demonstrate this in a Developer Sandbox, you can run the following execute anonymous code:

List<Account> accountList = new List<Account>();
Account accountObject;
for (Integer i = 0; i < 150; i++)
{
    accountObject = new Account();
    accountObject.Name = 'Test ' + i;
    accountList.add(accountObject);
}
insert accountList;

This will create 150 accounts. 

Now try to execute the following code:

Contact contactObject;
for (Account accountIterator : [SELECT Id, Name FROM Account])
{
    contactObject = new Contact();
    contactObject.AccountId = accountIterator.Id;
    contactObject.LastName = 'Surname ' + accountIterator.Name;
    insert contactObject;
}

Your execute anonymous should look like this:

You will hit the following error:

DML 150 Limit Fix

Again, it’s a fairly straightforward fix. You should not use DML statement inside for loops (by the way, this is something that good code scanning tools such as PMD will pick up on). Instead, you should leverage collections to store the data. Then, when you do a DML operation on a collection, it only counts as one DML!

To demonstrate, let’s execute the following code, and for good measure, let’s leverage some of the helpful methods from the limits class.

List<Contact> contactList = new List<Contact>();
Contact contactObject;
for (Account accountIterator : [SELECT Id, Name FROM Account LIMIT 150])
{
     contactObject = new Contact();
     contactObject.AccountId = accountIterator.Id;
     contactObject.LastName = ‘Surname ‘ + accountIterator.Name;
     contactList.add(contactObject);
}
If (contactList.size() > 0)
{ 
    Insert contactList;
}
system.debug(‘Size of contact list is: ‘ + contactList.size());
system.debug(‘Count of DML statements: ‘ + Integer.valueOf(Limits.getDmlStatements()));

Opening up the debug log will display the following:

That is very cool – you could have a collection with tens of thousands of records (or much more) and yet still only use one of your 150 available DML statements. Talk about efficient!

Governor Limits Practice Exercises

Practice makes perfect, so let’s do some exercises together. Good luck!

Question 1

How would you refactor this?

Task taskObject;
for (Contact contactObject : [SELECT Id, AccountId, LastName FROM Contact])
{
    taskObject = new Task(WhoId = contactObject.Id);
    insert taskObject;
}
[/code]

Answer 1

List<Task> tasks = new List<Task>();
Task taskObject;
for (Contact contactObject : [SELECT Id, AccountId, LastName FROM Contact])
{
    taskObject = new Task(WhoId = contactObject.Id);
    tasks.add(taskObject);
}
 
insert tasks;</pre>

<strong>Question 2</strong>

Question 2

How would you refactor this?

for (Account accountObject : [SELECT Id, Description FROM Account])
{
    Integer countOfEvents = [SELECT COUNT() FROM EVENT WHERE WhatId =: accountObject.Id];
    if (countOfEvents &amp;amp;amp;gt; 0)
    {
        accountObject.Description = String.valueOf(countOfEvents);
    }
    update accountObject;
}

[/code]

Answer 2

Map<Id, Account> accountsMap = new Map<Id, Account>([SELECT Id FROM Account]);
Set<Id> accountsWithEvents = new Set<Id>();
Map<String, String> eventsPerAccount = new Map<String, String>();
List<Account> accountList = new List<Account>();
 
for (Event eventObject : [SELECT Id, WhatId FROM Event WHERE WhatId IN : accountsMap.keySet()])
{
    accountsWithEvents.add(eventObject.WhatId);
}
for (AggregateResult aggregate : [SELECT COUNT(Id) theId, WhatId theWhatId FROM Event WHERE WhatId IN :accountsWithEvents GROUP BY WhatId])
{
    eventsPerAccount.put(String.valueOf(aggregate.get('theWhatId')), String.valueOf(aggregate.get('theId')));  
}
 
for (Account accountObject : [SELECT Id, Description FROM Account WHERE Id IN : eventsPerAccount.keySet()])
{
    if (accountObject.Description != eventsPerAccount.get(String.valueOf(accountObject.Id)))
      {
    accountObject.Description = eventsPerAccount.get(String.valueOf(accountObject.Id));
    accountList.add(accountObject);
      }
}
 
if (accountList.size() > 0)
{
    update accountList;
}
[/code]

The above answer is a way to achieve the outcome. It leverages AggregateResult and different collections to update the description field on the account object with the value of the number of event records that the account has.

Summary

In conclusion, there are many different types of governor limits across Salesforce and for good reason – to help us become more efficient developers and admins. There are some general patterns that you can adopt to ensure that you stay below the limits. Generally speaking, the most well-known limits are those around SOQL and DML limits in a single transaction. You also learned that getting past governor limits can be challenging and fun at the same time!

Thank you for reading, and check out the aforementioned Gist here.

The Author

Andy Hitchings

Andy is a certified Salesforce and DocuSign admin and a certified Salesforce developer. His favorite technologies right now are the Force.com platform and Javascript.

Comments:

    Raghavendra srinivas Philkana
    September 25, 2019 12:56 am
    Excellently written article .. great! Very important info put in simple amd easy to understand terms. Thank you so much :)
    Dux
    October 16, 2019 3:45 pm
    Thank you for the examples and code to make these concepts real in dev console.
    Eduard
    March 03, 2021 8:24 am
    Hey, thank you for the article. "That is very cool – you could have a collection with tens of thousands of records (or much more) and yet still only use 1 of your 150 available DML statements." - I am wondering isn't there a limit for a number of records allowed for dml? Total number of records processed as a result of DML statements - 10,000 https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_gov_limits.htm. Please advise.
    Eugene
    June 11, 2022 10:51 am
    Hi there. Links to answers for Questions 2 and 3 are leading to the Q1 answer. Thanks for the article!
    Rathindra Dakua
    July 03, 2022 9:56 pm
    The solution for Question 2 is quite impressive. I got to learn more about the "AggregateResult" object. Here are some articles about that:- https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_calls_query_aggregateresult.htm and https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_SOQL_agg_fns.htm
    Christine Marshall
    August 03, 2022 12:57 pm
    Thanks for letting us know! Links have been updated.

Leave a Reply