Back to Insights

Salesforce Governor Limits: understand, anticipate and work around them

Pierre Frin May 2026 10 min read
SOQL Queries 80% DML Statements 95% CPU Time 50% 100 SOQL max 150 DML max 10k SOQL rows 10s CPU Apex sync System.LimitException: Too many SOQL queries: 101 SALESFORCE · GOVERNOR LIMITS · APEX

Governor limits are one of the first things that surprise developers coming to Salesforce from other platforms. They impose strict ceilings on resources consumed by each Apex transaction, and exceeding them immediately raises an exception that rolls back execution. Understanding these limits means understanding how Salesforce really works.

Why governor limits exist

Salesforce is a multi-tenant platform, thousands of organisations share the same infrastructure. To ensure one client's code doesn't monopolise resources at others' expense, Salesforce enforces per-transaction limits on each resource type. This isn't a bug or artificial limitation, it's the mechanism that keeps the platform stable at scale.

Every time an Apex trigger fires, a Flow calls Apex code, or a batch runs, a resource counter starts. When a limit is reached, Salesforce raises a System.LimitException and rolls back the entire transaction.

The essential limits to know

SOQL Queries

100
Maximum SOQL queries per synchronous transaction. 200 in async context (batch, future, queueable).

SOQL Query Rows

50,000
Maximum records returned by all combined SOQL queries.

DML Statements

150
DML operations (insert, update, delete, upsert) maximum per transaction.

DML Rows

10,000
Maximum records modified by all combined DML operations.

CPU Time

10s / 60s
10 seconds synchronous, 60 seconds asynchronous. Pure Apex CPU time, excluding I/O.

Heap Size

6 MB / 12 MB
Memory allocated to the transaction: 6 MB synchronous, 12 MB asynchronous.

💡 Check limits in real time: the Limits class exposes current counters. Limits.getQueries() returns SOQL consumed, Limits.getLimitQueries() the maximum limit. Useful for instrumenting code and detecting overruns before they hit production.

The classic mistake : SOQL inside a loop

This is the most frequent mistake on Salesforce, and it catches even experienced developers coming from other languages. Putting a SOQL query inside a for loop consumes one query per iteration, and at 101 records, it's over.

❌ Pattern to avoid, SOQL inside a loop
// SOQL in loop = LimitException from 101 records
for (Account acc : trigger.new) {
    List<Contact> contacts = [
        SELECT Id, Email
        FROM Contact
        WHERE AccountId = :acc.Id  // ← one query per Account!
    ];
    // processing...
}
✅ Correct pattern, bulkified SOQL
// A single query for all records in the batch
Set<Id> accountIds = new Set<Id>();
for (Account acc : trigger.new) {
    accountIds.add(acc.Id);
}

Map<Id, List<Contact>> contactsByAccount = new Map<Id, List<Contact>>();
for (Contact c : [
    SELECT Id, Email, AccountId
    FROM Contact
    WHERE AccountId IN :accountIds  // ← a single query
]) {
    if (!contactsByAccount.containsKey(c.AccountId)) {
        contactsByAccount.put(c.AccountId, new List<Contact>());
    }
    contactsByAccount.get(c.AccountId).add(c);
}

DML inside a loop : same problem

The same mistake exists on the DML side. Doing an update or insert inside a loop consumes one DML operation per iteration. At 151 records, the limit is reached.

❌ DML inside the loop
for (Account acc : accountsToUpdate) {
    acc.Description = 'Updated';
    update acc;  // ← one DML per Account!
}
✅ Bulkified DML, a single operation
List<Account> toUpdate = new List<Account>();
for (Account acc : accountsToUpdate) {
    acc.Description = 'Updated';
    toUpdate.add(acc);
}
update toUpdate;  // ← a single DML for all

CPU Time : the intensive processing trap

The CPU time limit (10 seconds synchronous) only counts pure Apex execution time, not SOQL query wait time or HTTP call wait time. In practice, it's rarely hit on simple code, but becomes critical with:

The main workaround: go asynchronous. A @future, Queueable or Batchable has 60 seconds of CPU instead of 10.

Heap Size : memory and large collections

The heap size limit (6 MB synchronous) is often hit when loading large collections into memory, for example retrieving all fields with SELECT * or storing large lists in static variables.

Reference table

LimitSynchronousAsynchronousClassic mistake
SOQL Queries100200SOQL in loop
SOQL Rows50,00050,000SELECT without filter
DML Statements150150DML in loop
DML Rows10,00010,000Batch too large
CPU Time10s60sNested loops
Heap Size6 MB12 MBSELECT * on large object
HTTP Callouts100100Callout in trigger
Future methods50@future in loop

Strategies for working with limits

1. Always code in bulkified mode

Each Apex trigger can receive up to 200 records in the same batch. All code must be written to process a collection, never a single record. This is rule #1 of Apex development.

2. Go async for heavy processing

When processing risks exceeding synchronous limits, move it asynchronous. Salesforce offers several patterns:

3. Monitor limits with the Limits class

In development, instrumenting code with System.debug(Limits.getQueries()) allows monitoring real consumption and identifying hotspots before they reach production.

🚨 Watch out for cascading triggers: a trigger on object A that updates object B can fire a trigger on B, which updates C… Governor limits apply to the entire transaction, not each trigger individually. An uncontrolled cascade can exceed limits even with perfectly bulkified individual code.

Conclusion

Governor limits aren't an obstacle, they're guardrails that force writing performant, scalable code. A Salesforce developer who masters limits naturally writes bulkified code, thinks in terms of collections rather than individual records, and chooses the right async pattern for the context. This mastery is what distinguishes code that holds in production from code that breaks as soon as volume increases.

Pierre Frin
Founder Grokium · Salesforce Sales Cloud Consultant · 10 years experience

A Salesforce project to optimise?

Architecture, Apex development, code review, I can support you. Reply within 24 hours.

Let's talk →
Going further
My CRM services All technical articles Contact me