Salesforce Governor Limits: The Guide I Wish I Had on Day One

Understand SOQL, DML, CPU Time, and Heap Size through simple analogies, Apex examples, and practices that prevent the most common limit exceptions.

By Monique da Silva · July 21, 2026 · 7 min read

Salesforce Governor Limits represented as controls for shared computing resources

If you are new to Salesforce, sooner or later you will hear someone say, "we hit a limit," and wonder what that means. Let us understand the idea before it surprises you in a deployment or a production transaction.

First: why do the limits exist?

Salesforce is a multi-tenant platform. Your organization and thousands of other organizations run workloads on shared platform infrastructure.

Imagine an office building where every company shares the elevators, electricity, and internet connection. If one tenant attempts to consume an unreasonable amount of a shared resource, everyone else can be affected.

Governor Limits are execution boundaries that control how many resources a single transaction can consume. They protect the platform and require solutions to work efficiently at scale.

Governor Limits protect shared platform resources.
Before continuing: the values below describe a synchronous Apex transaction. Some limits are different for asynchronous execution, and Salesforce defines many more limits than the four introduced here. Always confirm current values in the official documentation.

1. SOQL limit: how many questions you can ask the database

Common synchronous limit: 100 SOQL queries per Apex transaction.

Every time your code sends a SELECT query to the database, it consumes part of that budget. If the transaction exceeds the limit, Salesforce stops the execution with a limit exception.

The analogy

Imagine a library where the librarian allows at most 100 requests per visit. Instead of returning to the desk 50 times for one book, you provide one list and ask for all relevant books together. One request, many results.

// AVOID: one query for every Account.
for (Account acc : accounts) {
    List<Contact> contacts = [
        SELECT Id, Name
        FROM Contact
        WHERE AccountId = :acc.Id
    ];
}

// BETTER: collect the IDs and query once.
List<Contact> contacts = [
    SELECT Id, Name, AccountId
    FROM Contact
    WHERE AccountId IN :accountIds
];
A safe beginner rule: avoid SOQL inside loops. Organize the input first and query records in groups, a practice known as bulkification.

2. DML limit: how many times you can write to the database

Common synchronous limit: 150 DML statements per Apex transaction.

DML includes operations such as insert, update, delete, and upsert. A statement counts whether it receives one record or a collection.

The analogy

Return to the library. If you return each of 200 books one at a time, you make 200 desk visits. If you place them on a cart and return the collection together, this analogy treats it as one operation.

// AVOID: one insert per record.
for (Contact con : newContacts) {
    insert con;
}

// BETTER: one insert for the collection.
insert newContacts;

The pattern is the same: loops combined with database access require careful design.

Do not confuse the limits: inserting a list counts as one DML statement, but the total number of records processed by DML has its own limit. Grouping operations does not make the volume unlimited.

3. CPU Time limit: how long your code can think

Common synchronous limit: 10,000 milliseconds, or 10 seconds, per Apex transaction.

This budget measures CPU time used by Apex and relevant automation invoked in the same transaction. Expensive loops, repeated transformations, and inefficient comparisons can consume it quickly.

The analogy

Imagine an exam with a strict ten-second timer. If the timer ends, the execution stops even if you were close to the answer.

// EXPENSIVE: every Account scans every Contact.
for (Account acc : accounts) {
    for (Contact con : allContacts) {
        if (con.AccountId == acc.Id) {
            // Do something
        }
    }
}

// BETTER: index Contacts by AccountId.
Map<Id, List<Contact>> contactsByAccount =
    new Map<Id, List<Contact>>();

for (Contact con : allContacts) {
    if (!contactsByAccount.containsKey(con.AccountId)) {
        contactsByAccount.put(con.AccountId, new List<Contact>());
    }
    contactsByAccount.get(con.AccountId).add(con);
}

for (Account acc : accounts) {
    List<Contact> relatedContacts = contactsByAccount.get(acc.Id);
    // Direct Map lookup instead of scanning the entire list again.
}

With 1,000 Accounts and 5,000 Contacts, the nested-loop approach can perform up to five million comparisons. The second approach scans the collections once and uses a Map for direct lookup.

4. Heap Size limit: how much memory your code can occupy

Common synchronous limit: 6 MB per Apex transaction.

Heap is the memory used by variables, collections, objects, strings, and other data that remain alive during execution.

The analogy

Imagine a fixed-size desk. Every document and tool you need must fit on it. If you keep too much in memory at the same time, you run out of space.

// RISKY: broad query with no filter and an unnecessary large field.
List<Contact> allContacts = [
    SELECT Id, Name, Description
    FROM Contact
];

// BETTER: filter and select only what the use case needs.
List<Contact> contacts = [
    SELECT Id, Name
    FROM Contact
    WHERE CreatedDate = THIS_MONTH
    LIMIT 500
];

A broad query may hit other limits before heap, such as the total number of SOQL rows. The answer is not to add an arbitrary LIMIT; filters and processing strategy must still satisfy the business requirement.

When a large data volume is genuinely required, Batch Apex can split the work into smaller transactions. Each execute invocation receives a fresh set of limits. The scope can be configured, and 200 records is the default batch size when none is specified.

Visual summary

LimitWhat it controlsCommon synchronous valueAnalogy
SOQLDatabase queries100Requests to the librarian
DMLWrite statements150Visits to the returns desk
CPU TimeProcessing time10 secondsExam timer
Heap SizeMemory in use6 MBDesk size

The pattern that keeps you safe

The four limits point to one principle:

Be efficient. Do more with fewer shared resources.
  • Do not query one record at a time. Query sets of records.
  • Do not write one record at a time. Group DML operations.
  • Do not compare everything with everything. Index data with Sets and Maps.
  • Do not load unnecessary data. Select only the required fields and rows.

Salesforce did not create Governor Limits to frustrate developers. They are part of how the platform protects a shared environment and encourages solutions that handle volume safely.

Once you learn to design for these boundaries, your code usually becomes clearer and more scalable on any platform.

Which Governor Limit was the hardest to understand when you started learning Apex?

Official sources for further study

Want to keep learning Salesforce and OmniStudio through hands-on content?

Explore my articles, OmniStudio 365, and the OmniStudio in Practice course.

Explore OmniStudio 365

About the author

I am Monique da Silva, a Salesforce professional focused on OmniStudio and Vlocity, with experience across functional analysis, declarative configuration, QA collaboration, training, and end-to-end delivery. I am also expanding my Apex, LWC, Agentforce, and Revenue Cloud skills.

I use this space to make technical concepts easier to understand and to share what I learn through practical examples. My YouTube channel includes OmniStudio lessons in English.