Types of Governor Limits in Salesforce

Types of Governor Limits in Salesforce

If you’ve worked in Salesforce long enough, you’ve probably run into an error that suddenly stops everything, something like “Too many SOQL queries” or “CPU time limit exceeded.” The first time it happens, it feels random. But it’s not. It’s Salesforce doing exactly what it was designed to do, enforcing Governor limits in Salesforce to keep the system stable.

Salesforce runs on shared infrastructure where thousands of companies operate at the same time. To prevent one org’s code from affecting others, the platform applies different types of governor limits in Salesforce.

In this blog, we’ll break down what those limits are, how they are categorized, and how to work with them more effectively.

What are Governor Limits in Salesforce?

In simple terms, governor limits are just boundaries within which your code runs. You don’t switch them on, and you can’t adjust them. They’re already part of how Salesforce operates.

Each time your logic executes, it can only use a certain amount of system resources. When that usage goes beyond what’s allowed, Salesforce simply ends the execution instead of letting it continue.

Those limits apply to things like how often you can hit the database, how many records you can modify at once, and how long the logic keeps running. Most of the time, you won’t notice them while testing small scenarios.

They become obvious when the same logic handles a larger data set and suddenly fails. That’s usually when it clicks. Governor limits quietly shape how responsibly we write code on the platform.

Types of Governor Limit in Salesforce

Image Credit: Salesforce

Types of Governor Limits in Salesforce

Governor limits are not a single restriction. They show up in different ways depending on what your code is doing and where it is running. Once you see how they are grouped, it becomes easier to make smarter design decisions and avoid those surprise runtime errors.

1. Per-Transaction Apex Limits

These are the limits most developers run into first. They apply to a single run of your code, from the moment it starts until it finishes. If that run consumes more resources than it’s allowed, Salesforce immediately ends the transaction and reverses any changes made during that process.

This category includes limits around how many SOQL queries you can run, how many DML statements you can execute, how much CPU time your logic consumes, how much heap memory is used, and how many callouts are made.

The important thing to remember is that these limits reset with each new transaction. So if a trigger handles 200 records in one go, everything inside that run shares the same limit pool.

2. Static Limits

Static limits work a little differently. They are not related to one transaction. They are connected to how your org is structured overall. You can think of them as limits built into the foundation of your setup.

For example, there is a maximum total size allowed for Apex code in an org, limits on how many classes or triggers you can deploy at once, and restrictions on method size. These do not reset with transactions because they are not about runtime usage. They define how much customization your org can hold.

3. Size-Specific Limits

Some limits focus more on data size rather than the number of operations. These come into play when you are working with large responses, heavy processing, or integrations.

Heap size during execution, email attachment limits, file upload size, and callout request or response size fall into this category. When handling large datasets or external payloads, these limits can become the deciding factor in how you design your solution.

4. API Limits

Whenever your Salesforce org starts talking to another system, limits still apply. Every API request that goes in or out counts toward a daily allowance. If that allowance is exhausted, integrations simply stop working until the limit resets.

This usually becomes noticeable in projects where there are frequent sync jobs, middleware tools, or bulk data loads running throughout the day. In those cases, it’s not just about writing good Apex. It’s also about understanding how often your org is calling or being called by something else.

5. Asynchronous Apex Limits

Everything in Salesforce does not have to run the moment a user clicks Save. Some tasks can be moved to the background using Future methods, Queueable Apex, or Batch Apex. When this happens, the work runs separately instead of being tied directly to the user’s action.

Since these jobs do not hold up the screen for someone, Salesforce allows them to use more resources. They get more time to run, more room for queries, and more memory compared to regular synchronous code. That is why larger data updates or heavier logic are usually handled asynchronously rather than inside a trigger.

Governor Limits Cheat Sheet

Per-Transaction Apex Limits

Description Synchronous Limit Asynchronous Limit
Total number of SOQL queries 100 200
Total number of SOSL queries 20 20
Total number of DML statements 150 150
Total records retrieved by SOQL 50,000 50,000
Total records retrieved by a single SOSL query 2,000 2,000
Records retrieved via Database.getQueryLocator  10,000 Up to 50 million (Batch Apex)
Total heap size 6 MB 12 MB
Maximum CPU time 10,000 ms 60,000 ms
Maximum future method calls 50 N/A (already async)
Maximum cumulative callout timeout 120 seconds 120 seconds

Static Apex Limits

Description Limit
Default callout timeout 10 seconds
Max callout request/response size 6 MB (sync) / 12 MB (async)
Maximum SOQL query runtime 120 seconds
Max Apex classes & triggers per deployment 7,500
Apex trigger batch size 200 records
For-loop list batch size 200 records
Max records returned in Batch Apex (Query Locator) 50 million

Synchronous vs Asynchronous Governor Limits in Salesforce

What Is a Synchronous Transaction Governor Limit?

A synchronous transaction is the kind of processing that happens immediately when a user performs an action. You click Save, and a trigger runs. You press a button, Apex executes. The system processes everything in real time and returns a response right away.

Because this execution is directly tied to what the user is waiting for, Salesforce keeps stricter limits around it. There is a cap on how many queries can run, how much CPU time is used, and how much memory can be consumed.

For example, synchronous Apex allows up to 100 SOQL queries, about 10 seconds of CPU time, and 6 MB of heap size. The idea is straightforward. One user action should not slow down the entire system.

What Is an Asynchronous Transaction Governor Limit?

Asynchronous processing works differently. Instead of running immediately in front of the user, the task is sent to the background. The user can continue working while the job completes separately.

This approach is used in Future methods, Queueable Apex, Batch Apex, and Scheduled Apex. Since these jobs are not blocking the interface, Salesforce gives them more flexibility. They can use more CPU time, run more queries, and handle more memory.

For instance, asynchronous Apex allows up to 200 SOQL queries, around 60 seconds of CPU time, and a larger heap size.

That is why operations involving large data volumes, heavy integrations, or complex processing are usually designed to run asynchronously instead of being forced into a synchronous transaction.

How to avoid hitting Governor Limits in Salesforce?

Understanding governor limits is important. But knowing how to avoid hitting them is what actually makes you a strong Salesforce developer.

Here are the practical design principles with types of governor limits that help you stay safe.

1. Always Bulkify Your Code

Salesforce processes records in batches (up to 200 at a time). Your code should be written assuming multiple records are being processed and not just one.

That means:

  • Never write logic assuming a single record
  • Always use collections (List, Set, Map)
  • Design triggers to handle bulk operations

Example – Not Bulkified (Single-Record Mindset)

trigger AccountTrigger on Account (after insert) {
 for (Account acc : Trigger.new) {
  Contact con = new Contact( LastName = acc.Name, AccountId = acc.Id ); 
  insert con; 
  } 
}

If 200 Accounts are inserted → 200 DML statements → limit exceeded.

Bulkified Version

trigger AccountTrigger on Account (after insert) { 
 List<Contact> contactsToInsert = new List<Contact>(); 
 for (Account acc : Trigger.new) {
  contactsToInsert.add(new Contact( LastName = acc.Name, AccountId = acc.Id )); 
 }
 insert contactsToInsert; // One DML 
}

2. Never Write SOQL or DML Inside Loops

This is the most common mistake.

Bad pattern:

  • Loop through records
  • Run a query for each record
  • Perform DML for each record

Correct pattern:

  • Collect IDs in a Set
  • Run one query outside the loop
  • Perform one DML on a list

This single principle alone prevents most governor limit errors.

Example – Wrong Way (SOQL Inside Loop)

for (Account acc : Trigger.new) { 
  List<Contact> cons = [SELECT Id FROM Contact WHERE AccountId = :acc.Id];
}

If 100 records → 100 queries → limit reached.

Correct Way

Set<Id> accIds = new Set<Id>(); 
for (Account acc : Trigger.new) { 
  accIds.add(acc.Id); 
}
 List<Contact> cons = [SELECT Id, AccountId FROM Contact WHERE AccountId IN :accIds];

3. Use Maps for Faster Lookups

Instead of running multiple queries to fetch related data, use a Map.

For example:

  • Query all related records once
  • Store them in a Map<Id, Object>
  • Access them efficiently inside loops

This reduces queries and improves performance.

Example – Inefficient Lookup

for (Account acc : Trigger.new) { 
 for (Contact con : cons) { 
  if (con.AccountId == acc.Id) {
   // logic } 
  } }

Nested loops increase CPU time.

Efficient Map-Based Lookup

Map<Id, List<Contact>> accContactMap = new Map<Id, List<Contact>>();
  for (Contact con : cons) {
   if (!accContactMap.containsKey(con.AccountId))
   { 
    accContactMap.put(con.AccountId, new List<Contact>());
   }
  accContactMap.get(con.AccountId).add(con); }

4. Move Heavy Logic to Asynchronous Apex

If your transaction:

  • Processes thousands of records
  • Makes multiple callouts
  • Performs complex calculations

Move it to:

  • Queueable Apex
  • Batch Apex
  • Scheduled Apex

Async processing gives you higher limits and keeps the user experience smooth.

Example – Using Queueable Apex

public class HeavyProcessing implements Queueable {
    public void execute(QueueableContext context) {
        // Heavy logic here
    }
}

Call from trigger:

System.enqueueJob(new HeavyProcesing());

5. Optimize Your Queries

Even if you stay within 100 queries, poorly written SOQL can still cause performance issues.

Best practices:

  • Select only the required fields
  • Use indexed fields in WHERE clauses
  • Avoid unnecessary subqueries
  • Avoid large data loads into memory

Efficient queries reduce CPU time and heap usage.

Example – Bad Query (Fetching Unnecessary Fields)

SELECT Id, Name, Description, CreatedDate, LastModifiedDate, BillingAddress, ShippingAddress FROM Account

Optimized Query

SELECT Id, Name FROM Account WHERE IsActive__c = true

Fetch only what you actually need.

6. Avoid Recursive Automation

Sometimes CPU time errors are not caused by Apex, but by:

  • Triggers calling updates
  • Updates firing flows
  • Flows firing processes
  • Processes calling Apex again

This chain reaction increases CPU time.

Always implement recursion control in triggers and review automation carefully.

Recursive Trigger Example

trigger AccountTrigger on Account (after update) {
    for (Account acc : Trigger.new) {
        acc.Description = 'Updated';
    }
    update Trigger.new;
}

This causes the trigger to fire again → recursion.

Controlled Recursion

public class TriggerHelper {
    public static Boolean isFirstRun = true;
}

trigger AccountTrigger on Account (after update) {
    if (TriggerHelper.isFirstRun) {
        TriggerHelper.isFirstRun = false;

        List<Account> updates = new List<Account>();
        for (Account acc : Trigger.new) {
            acc.Description = 'Updated';
            updates.add(acc);
        }
        update updates;
    }
}

7. Use Limits Class for Monitoring

Salesforce provides a Limits class to check usage in real time.

For example:

  • Limits.getQueries()
  • Limits.getDmlStatements()
  • Limits.getCpuTime()

This helps during debugging and optimization.

Example –

System.debug(‘SOQL Used: ‘ + Limits.getQueries());

System.debug(‘DML Used: ‘ + Limits.getDmlStatements());

System.debug(‘CPU Time Used: ‘ + Limits.getCpuTime());

Also Read – Omnistudio Interview Questions and Answers

FAQs

1. Can Governor Limits Be Increased?

No. Governor limits are enforced by the Salesforce platform and cannot be increased by request. However, you can redesign your solution by using asynchronous Apex.

2. Do Governor Limits Reset?

Yes, but it depends on the context.

  • Per-transaction limits reset with every new transaction.
  • In Batch Apex, limits are reset for every batch execution.
  • API limits reset daily based on your org’s allocation.

3. What if the Governor Limit Is Exceeded?

Salesforce immediately stops the execution and throws a runtime exception. The entire transaction is rolled back. This means:

  • No partial data is saved.
  • All DML operations in that transaction are undone.

4. What Is the Most Common Governor Limit Error?

In real projects, the most common errors are:

  • Too many SOQL queries: 101
  • Too many DML statements: 151
  • CPU time limit exceeded

5. Is It Possible to Hit Limits Without Writing Apex?

Yes. Flows, Process Builder, validation rules, managed packages, and other automations all contribute to CPU time and transaction limits. Even if your Apex is optimized, excessive automation can still cause failures.

Conclusion

Governor limits exist to keep the platform stable for everyone using it. Once you spend some time working with them, you start to see patterns. Most errors are not random. They usually come from assumptions made during design.

By bulkifying the code, you move heavier logic to asynchronous processing when needed, and limit issues that become far less common. Over time, working within these boundaries becomes part of your normal development approach rather than something you worry about.

Get a complete Roadmap to Learn Salesforce Admin and Development👇

Share Now

Learn Salesforce Flows 👇 Beginner-friendly course | More than 90+ tutorials

Prepare for PD1 Exam 3 Mock Practice Sets to prepare for the exam

Book a 1:1 Call 👇 Doubt related to Salesforce Flow?

Categories

What’s Trending