Salesforce governor limits are caps that the Apex runtime enforces on every transaction: how many SOQL queries and DML statements your code may run, how many records it may touch, and how much CPU time and memory it may use. Because Salesforce is multitenant, the limits stop one org's code from slowing down everyone else. Exceed one and the transaction fails with an exception that can't be caught.
This guide was first published in 2020. It has been rewritten for 2026 with the current per-transaction table, including Salesforce's higher heap limit, and the coding patterns that keep you inside the limits.
What are governor limits in Salesforce?
Governor limits are runtime caps on each Apex transaction, enforced so that shared, multitenant servers stay fair for every customer. Salesforce runs many customers' code on shared servers. Its Execution Governors and Limits article explains that the Apex runtime engine strictly enforces limits so that runaway Apex code or processes don't monopolise shared resources. If code exceeds a limit, the governor issues a runtime exception that can't be handled, and the whole transaction rolls back.
Limits apply per transaction: everything that runs from one starting point, such as a record save from the UI, an API call or a batch chunk, including every trigger, flow and class it sets off. For Batch Apex, the limits reset for each execution of the execute method.
Salesforce governor limits table (per transaction)
As of November 2026, the key per-transaction limits are 100 SOQL queries (200 asynchronous), 150 DML statements, 10,000 records processed by DML, 10 seconds of CPU (60 asynchronous) and a 10 MB heap (25 MB asynchronous).
| Limit | Synchronous | Asynchronous |
|---|---|---|
| SOQL queries issued | 100 | 200 |
| Records retrieved by SOQL queries | 50,000 | 50,000 |
| Records retrieved by Database.getQueryLocator | 10,000 | 10,000 |
| SOSL queries issued | 20 | 20 |
| Records retrieved by a single SOSL query | 2,000 | 2,000 |
| DML statements issued | 150 | 150 |
| Records processed by DML | 10,000 | 10,000 |
| CPU time on Salesforce servers | 10,000 ms | 60,000 ms |
| Total heap size | 10 MB | 25 MB |
| Callouts (HTTP or web service) | 100 | 100 |
| Cumulative timeout for all callouts | 120 seconds | 120 seconds |
| Future methods per invocation | 50 | 0 in batch and future contexts; 50 in Queueable |
| Jobs added with System.enqueueJob | 50 | 1 |
| sendEmail calls | 10 | 10 |
| Stack depth for recursive trigger calls | 16 | 16 |
| Maximum execution time per transaction | 10 minutes | 10 minutes |
Figures from Salesforce Help's Execution Governors and Limits and the matching Apex Developer Guide page, checked on 10 November 2026. CPU time counts only time on Salesforce's application servers: database work such as SOQL, DML and SOSL, and waiting for callouts to return, do not count towards it. The default timeout of a single callout is 10 seconds, email services have a 50 MB heap, and a Batch Apex QueryLocator can return up to 50 million records.
Note on heap size: for years the heap limit was 6 MB synchronous and 12 MB asynchronous, and older versions of the Apex Developer Guide still show those numbers. The Winter '27 release note raises them to 10 MB and 25 MB, and says the higher limits apply to every org, whatever its setting, from Spring '27. Until then, check the limit your org enforces with Limits.getLimitHeapSize() before relying on the extra room. The article also warns that heap and CPU are related: code close to both limits is more likely to hit the CPU limit, because heap checks cost CPU time.
Org-wide limits that run across transactions
Some limits apply to the whole org rather than one transaction. The Apex Developer Guide lists, among others:
| Org-wide limit | Value |
|---|---|
| Asynchronous Apex executions (Batch, future, Queueable, scheduled) per 24 hours | 250,000, or 200 times the number of applicable user licences, whichever is greater |
| Batch Apex jobs queued or active at the same time | 5 |
| Batch Apex jobs held in the Apex flex queue | 100 |
API calls have their own daily allocation by edition and licence. Check live usage in Setup under System Overview, or through the REST API's Limits resource.
Why do governor limits exist?
Governor limits exist because thousands of orgs share the same infrastructure. In a single-tenant system, bad code slows down only its owner. In Salesforce, thousands of orgs share the same infrastructure, so an endless loop or an unbounded query in one org could affect others. Governor limits make every transaction predictable. They also push developers towards code that scales: a trigger that works for one record but breaks for 200 is a bug whether or not limits exist.
The governor limit errors you will see most
Five errors cause most limit failures, and almost all trace back to queries, DML or loops written for one record instead of many.
| Error | Usual cause | Usual fix |
|---|---|---|
| Too many SOQL queries: 101 | A query inside a loop, or several triggers each querying the same data | Query once before the loop; share results through a map or a static cache |
| Too many DML statements: 151 | insert or update inside a loop | Add records to a list and run one DML statement after the loop |
| Too many DML rows: 10001 | Updating a large number of related records in one transaction | Move the work to Batch or Queueable Apex |
| Apex CPU time limit exceeded | Nested loops, heavy string work, too much automation on one object | Use maps instead of nested loops, consolidate triggers and flows, go asynchronous |
| Apex heap size too large | Holding large query results or files in memory | Query only needed fields, use SOQL for loops, process in batches |
How to avoid governor limits: bulkification
You avoid governor limits mainly by bulkifying: writing code that handles 200 records as easily as one. Trailhead's Bulk Apex Triggers unit is the best short guide; our Apex trigger guide covers triggers in full. Its core points:
- Assume many records. Triggers execute on batches of 200 records at a time; 400 records fire the trigger twice. Always loop over
Trigger.new, never just the first record. - No SOQL inside loops. Query once for all the records in the trigger, filtered with
WHERE Id IN :Trigger.new, and loop over the results. - No DML inside loops. Collect changed records in a
Listand run one DML statement after the loop. - Use maps for lookups.
Map<Id, Account>built from a query replaces nested loops and saves CPU time; our guide to Apex collections explains lists, sets and maps.
The difference in practice:
Breaks at scale: for (Opportunity o : Trigger.new) { Account a = [SELECT Name FROM Account WHERE Id = :o.AccountId]; } runs one query per record, so 101 records fail.
Bulk-safe: collect the account IDs into a Set<Id>, run Map<Id, Account> accts = new Map<Id, Account>([SELECT Name FROM Account WHERE Id IN :ids]); once, then read from the map inside the loop. One query, whatever the batch size.
More ways to stay inside the limits
Beyond bulkification, structure, asynchronous processing and measurement keep code inside the limits.
- One trigger per object, calling a handler class, so you control the order and avoid repeated queries.
- Go asynchronous for heavy work. Asynchronous Apex gets 200 queries, 60 seconds of CPU and a larger heap; Batch Apex resets the limits for every chunk.
- Select only the fields you need and filter on indexed fields, which saves heap and query rows.
- Use SOQL for loops (
for (Account a : [SELECT ...])) for large result sets, so records are processed in chunks rather than held in memory at once. - Watch flows as well as code. Salesforce Help's per-transaction flow limits article says autolaunched flows share the limits of the transaction that launched them, and the triggers and flows they set off count against the same limits. Salesforce's record-triggered automation guide advises one automation entry point per object and avoiding a mix of Flow and Apex triggers on the same object; the order of execution shows how they stack up in one save.
- Measure. The
Limitsclass, for exampleLimits.getDMLStatements(), shows consumption while code runs. Test with 200 or more records, not one.
Getting help
Techila is a Salesforce Summit Partner. Our Salesforce development services team reviews and refactors Apex and automation that hits governor limits, and builds new code bulk-safe from the start. Talk to us if limit errors are slowing your users or your integrations.
Frequently asked questions
What are governor limits in Salesforce?
Governor limits are caps the Apex runtime enforces on each transaction, such as the number of SOQL queries, DML statements, records processed, CPU time and memory. Because Salesforce is multitenant, the limits stop one customer's code from monopolising shared resources.
How many SOQL queries can you run in one Salesforce transaction?
100 in synchronous Apex and 200 in asynchronous Apex, such as Batch, Queueable or future methods. Queries can return up to 50,000 records in total per transaction.
What happens when you exceed a governor limit?
The governor throws a System.LimitException, which can't be caught. The whole transaction is rolled back, so nothing it changed is saved, and the user or integration sees an error.
What is the heap size limit in Apex?
The Winter '27 release raised it from 6 MB to 10 MB for synchronous and from 12 MB to 25 MB for asynchronous Apex. Salesforce's release note says the higher limits apply to every org from Spring '27, so until then check yours with Limits.getLimitHeapSize(), and keep large collections small either way.
How do you avoid hitting governor limits?
Write bulkified code: query and update records in collections, never inside loops; filter queries tightly; use maps for lookups; move heavy work to Batch or Queueable Apex; and check consumption with the Limits class during testing.
