Apex Governor Limits: Salesforce Code Design Guide

Salesforce runs Apex in a multitenant environment where many organizations share platform resources. That design makes resource discipline a platform requirement rather than an optional coding preference. Governor limits place hard, per-transaction ceilings on operations such as SOQL queries, DML statements, returned rows, CPU time, and heap usage so that one inefficient transaction cannot consume an unreasonable share of shared resources. These limits apply to Apex transactions across org sizes and editions. Core per-transaction limits are not increased simply because an organization has a larger contract or opens a routine support case.

Developers often encounter governor limits when code that behaved well with a small test dataset is exposed to bulk processing. A trigger can appear correct with one record and then throw “Too many SOQL queries: 101” when a transaction contains a full trigger batch. Designing around limits from the start is safer than treating them as production errors to patch later. The practical work is to understand what each limit measures, know which limits change by execution context, bulkify data access, control repeated automation, select the right asynchronous mechanism, and test with realistic transaction sizes. This guide focuses on the limits that matter most in day-to-day Salesforce development and the design choices that keep resource use predictable as data volume and automation density increase.
TL;DR

  • Governor limits are hard per-transaction caps on SOQL queries, DML statements, CPU time, and heap size, and no org can get them raised
  • Crossing a limit throws an uncatchable System.LimitException and rolls back the entire transaction, not just the offending line
  • Asynchronous Apex receives higher allowances for selected resources, including SOQL queries and CPU time, while several other per-transaction limits remain the same.
  • A common cause of limit failures is a SOQL query or DML statement running inside a loop.
  • Bulkifying code, querying and updating once per transaction instead of once per record, fixes that root cause directly
  • A trigger handler pattern with a recursion guard stops the same logic from firing multiple times in 1 transaction
  • Batch Apex, Queueable classes, and future methods each suit a different kind of heavy or large-volume work
  • Testing with 200 records is an important bulk boundary test, alongside realistic automation and heavy execution paths that can expose bulk-related problems before production does.

What Governor Limits Are, and Why Salesforce Enforces Them

A governor limit is a hard ceiling Salesforce applies to a single Apex transaction. Depending on the limit, it can restrict the number of SOQL queries, the total rows returned by SOQL, the number of DML statements, the total rows processed by DML, CPU time, heap usage, callouts, or other resource-consuming operations. If a transaction exceeds a hard governor limit, Salesforce raises a runtime limit exception and stops the transaction. The same core per-transaction governor limits apply regardless of how large the org is or how much the customer pays for Salesforce.

The reason comes from Salesforce’s multi-tenant architecture. Many organizations use the same underlying platform infrastructure, so the runtime has to prevent one transaction from monopolizing shared application and database resources. Without enforced ceilings, an inefficient loop, repeated trigger execution, an unnecessarily broad data operation, or a large in-memory workload could place disproportionate pressure on the platform. Governor limits make resource consumption predictable by stopping transactions that cross defined ceilings instead of allowing them to continue consuming resources indefinitely.

That behavior can feel strict compared with frameworks where an application controls its own server resources. Apex does not provide a grace period after a hard per-transaction limit has been exceeded. Once the runtime reaches a nonrecoverable limit condition, the transaction fails and uncommitted database work is rolled back. Developers can still monitor usage before that point through the Limits class, debug logs, tests, and performance analysis, but those tools help prevent a breach rather than soften one after it occurs.

Limits are evaluated within transaction boundaries rather than as one shared daily budget for every line of Apex in an org. A user request, trigger transaction, Queueable job, future invocation, and each Batch Apex execute invocation can have a separate per-transaction allowance. Some org-level limits, especially around asynchronous execution, also exist and should not be confused with per-transaction limits. During a Salesforce implementation, understanding where one transaction ends and another begins is as important as memorizing individual numbers, because moving work to a new execution context changes both timing and the resource budget available to that work.

Synchronous vs Asynchronous Limits, Side by Side

Not every Apex execution context uses the same per-transaction limits. Synchronous Apex, including code running as part of a user request, a Salesforce Lightning interaction, or a normal trigger transaction, uses the synchronous limits. Asynchronous Apex such as Queueable Apex, future methods, and Batch Apex generally receives a separate transaction and higher allowances for selected resources, including SOQL query count and CPU time. Scheduled Apex is an important exception: although scheduling is asynchronous from the user’s point of view, the scheduled job itself runs with synchronous governor limits. The table below summarizes the limits that most often shape Apex design, using Salesforce’s current governor limits reference and noting the Winter ’27 heap change separately.

LimitSynchronousAsynchronous
SOQL queries per transaction100200
Total rows retrieved by SOQL50,00050,000
SOSL queries per transaction2020
DML statements per transaction150150
Total rows processed by DML10,00010,000
CPU time10,000 milliseconds60,000 milliseconds
Heap size (Winter ’27 when enabled)10 MB25 MB

Heap size needs release-specific wording because Salesforce is increasing it in Winter ’27. For orgs where the Winter ’27 change is enabled, the synchronous heap limit rises from 6 MB to 10 MB and the asynchronous heap limit rises from 12 MB to 25 MB. Salesforce is enabling the change according to each org’s Winter ’27 release schedule, so an org that has not received the release can still report the earlier 6 MB and 12 MB values. Developers can confirm the active ceiling in code with Limits.getLimitHeapSize() instead of assuming every org is already on the new value.

The table also shows why it is better to learn the individual limits than to say asynchronous Apex simply gets “double” the synchronous budget. SOQL queries rise from 100 to 200, while CPU time rises from 10,000 milliseconds to 60,000 milliseconds. Other limits, including total SOQL rows, DML statements, and DML rows, remain the same. Heap is 10 MB versus 25 MB after the Winter ’27 increase is active. Moving work asynchronously can create more headroom and a separate transaction, but it does not remove the need for bulk-safe queries, bounded loops, controlled memory use, and deliberate job design.

What Happens When Your Code Crosses a Limit

When a hard Apex governor limit is exceeded, Salesforce raises System.LimitException. A governor-limit exception cannot be handled in the same way as a normal application exception by wrapping the offending line in a try-catch block. The runtime terminates the transaction, and uncommitted database changes made in that transaction are rolled back. That makes prevention essential: once code crosses a hard limit, there is no local error-handling branch that can continue the same transaction safely.

The rollback behavior matters because limit consumption is cumulative across the transaction. Suppose a bulk update enters a trigger, related automation performs additional work, and the combined logic eventually processes more than 10,000 DML rows in that one transaction. The failure can occur after earlier statements have already run, but the transaction still does not keep a partially committed result. Developers therefore need to reason about the combined work performed by triggers, flows, helper classes, and other automation in the same transaction. Shared limits such as CPU time and heap usage can be consumed across that transaction. Certified managed packages installed from Salesforce AppExchange receive separate namespace allocations for many per-transaction limits, including SOQL queries and DML statements, subject to cumulative cross-namespace ceilings. CPU time, heap, maximum transaction time, and certain other limits remain shared. The production errors most teams recognize include:

●   Too many SOQL queries: 101, which means a synchronous transaction attempted a 101st SOQL query

●   Too many DML statements: 151, which means the transaction attempted more than the allowed 150 DML statements

●   Apex CPU time limit exceeded, which means application-server processing consumed more CPU time than the execution context allows

●   Apex heap size too large, which means the transaction held more data in Apex memory than the active heap limit permits

●   Too many query rows: 50,001, which means the combined SOQL result rows in the transaction exceeded the 50,000-row limit

Each message points toward a different resource, but the underlying design problem is often similar: resource consumption scales with the number of records or with repeated automation instead of remaining bounded. The right response is not to catch the limit exception after it happens. The code has to be changed so queries, DML, loops, memory use, and asynchronous boundaries stay within a predictable budget for the largest transaction the design is expected to handle.

The Root Cause: Queries and DML Inside Loops

One of the most common ways to exceed Apex governor limits is placing a SOQL query or DML statement inside a loop that runs once for each record. The pattern can look harmless when a developer tests one record. If a trigger queries a related object separately for every incoming record, a transaction containing 200 trigger records can attempt 200 queries. A synchronous transaction is limited to 100 SOQL queries, so that design fails before the batch finishes even though the business logic itself may be simple.

DML inside a loop creates the same scaling problem for writes. If code calls update once for every record, 151 iterations are enough to exceed the 150-DML-statement limit. The issue is not that Apex cannot update many records. One DML statement can operate on a collection of records, subject to the transaction’s DML-row limit. The problem is issuing a separate database operation for each item when the work can be grouped into a bounded number of collection operations.

Small development datasets can hide this defect. A sandbox test with one or two records may never push the query or DML count high enough to expose it, while a bulk API request, data migration, Salesforce integration, or mass update can place many records into the same execution context. Salesforce’s bulk behavior does not make the flaw invisible; it exposes a flaw that low-volume testing failed to exercise. That is why code review and bulk-focused tests both matter even when manual testing appears clean.

The practical default is to assume that trigger logic and reusable data-access logic can be called with collections and can share a transaction with other automation. Queries should therefore be planned around sets of keys, DML should operate on lists, and helper methods should avoid hidden record-by-record database work. That approach keeps the number of database operations tied to the shape of the logic rather than to every individual record that happens to enter the transaction.

Bulkification: The Pattern That Fixes It

Bulkification means structuring Apex so resource-intensive operations work on collections and remain bounded as record count increases. It does not mean that every transaction must contain exactly one query or exactly one DML statement. A realistic transaction can require several queries and several writes. The important distinction is that those operations are performed outside record-by-record loops and are designed around collections, so the query and DML counts do not grow linearly with every input record.

In a typical trigger, the code first collects the identifiers or field values it needs into a Set. It then runs a SOQL query that retrieves the related records for the full set and stores those results in a Map or another collection that supports efficient lookup. The trigger loop can then use the in-memory collection instead of querying again for each record. For writes, records that need to change are accumulated in a List and passed to a DML statement after the loop. This design can still use more than one query or DML operation where the business logic requires it, but the operations remain intentionally bounded.

Bulk-safe code also needs to account for row limits, heap use, CPU work, and downstream automation. Moving a query outside a loop fixes one class of problem, but a query that retrieves unnecessary fields or tens of thousands of rows can still create memory and processing pressure. Similarly, collecting every possible record into one large list is not automatically safe simply because the final update uses one DML statement. Good bulkification combines collection-based database access with appropriate filtering, controlled in-memory structures, and transaction sizes that match the job.

The same principles apply outside triggers. Queueable jobs, Batch Apex execute methods, invocable Apex called from Flow, REST endpoints, controller methods, and reusable service classes can all receive multiple records or be called from a transaction that has already consumed part of its governor budget. Designing those methods for collections and keeping database work bounded makes them more predictable when the surrounding automation changes or data volume increases.

Trigger Design and Recursion Control

Bulkification controls record-volume scaling, but triggers can still consume limits through repeated execution in the same transaction. An after-update trigger that performs another update can cause the save cycle to run again. In Salesforce Sales Cloud, for example, an Opportunity update can cascade into related automation that writes back to the same or connected records. If the trigger’s business logic executes again even though the relevant condition has not changed, queries, DML, CPU work, and downstream automation can be repeated. A trigger can therefore be bulk-safe in isolation and still fail because the same work is performed more times than the design expected.

Recursion control should start with the business condition that makes the work necessary. Salesforce architecture guidance recommends gating update logic by comparing the new and old record values when possible, so the code runs only when the field or state that matters has actually changed. That field-change check is more precise than a transaction-wide static Boolean because it allows valid records to be processed while preventing redundant work. A trigger handler pattern can still centralize orchestration, and static variables or processed-ID collections can be useful for transaction state or deduplication, but they should support a deliberate idempotent design rather than act as a blanket switch that assumes the logic must run only once.

This distinction matters in bulk transactions. A single static Boolean can suppress later legitimate work if the same handler is entered more than once for different records or phases of processing. A condition based on Trigger.oldMap and Trigger.new, by contrast, expresses why the logic should execute and prevents a second pass when the relevant field has not changed. Where repeated expensive computation also needs to be avoided, a static Set of processed identifiers or cached results can provide narrower transaction-level control without treating every re-entry as invalid.

Many teams also use one trigger per object with a handler framework so execution order, bypass rules, shared state, and test coverage can be managed from a known location. That is an architecture convention rather than a Salesforce platform requirement, but it can reduce uncertainty in orgs with dense automation. The objective is to make repeated work visible and controllable, regardless of the exact framework a team chooses.

Choosing the Right Execution Context for Heavy Work

Some workloads should not stay in the synchronous request that started them. Large integrations, long-running calculations, Salesforce maintenance and support jobs, and high-volume record processing can be easier to govern when they run in a separate transaction. The choice is not simply “sync versus async.” Queueable Apex, Batch Apex, future methods, and Scheduled Apex have different execution behavior, monitoring options, chaining rules, and governor-limit implications. Selecting the mechanism that matches the workload can prevent a design from consuming the wrong budget or creating unnecessary operational complexity.

ContextBest suited forKey limit consideration
Future methodLegacy/simple asynchronous work; Queueable is preferred for most new designsUp to 50 future invocations can be requested from a synchronous transaction; limited job visibility and no chaining
Queueable ApexBackground processing that needs job tracking, complex state, callouts, or chainingAsynchronous per-transaction limits apply; only 1 Queueable can be enqueued from an asynchronous transaction
Batch ApexLarge datasets processed across separate execute transactionsPer-transaction limits reset for each execute invocation; scope should be tuned to workload cost
Scheduled ApexWork that must start on a recurring scheduleScheduled Apex executes with synchronous governor limits when the scheduled job runs

Batch Apex is designed for workloads that need to process large datasets in separate chunks. The per-transaction governor limits are reset for each invocation of the execute method, so the job does not spend one SOQL, DML, CPU, and heap allowance across its entire dataset. That reset is one of Batch Apex’s main strengths for high-volume processing. The batch scope should still be chosen intentionally: 200 is a common default, but smaller or otherwise tuned scopes can be appropriate when each record carries high CPU, heap, callout, or downstream-automation cost. Reducing scope should be a measured design choice, not a substitute for fixing avoidable inefficiency.

Apex Cursors add another option for large result sets. They became generally available in Spring ’26 and allow code to fetch portions of a query result from controlled positions. A cursor can be serialized and passed through chained Queueable jobs, which gives developers a flexible alternative to Batch Apex for some workloads. The cursor controls how records are retrieved; the Queueable logic can still process those records and perform downstream operations subject to the governor limits of each Queueable transaction. Batch Apex remains useful when its lifecycle, job management, and chunked processing model fit the requirement, while Cursor plus Queueable can be attractive when flexible fetch sizes, position control, or custom chaining are more important.

Writing Selective Queries That Hold Up as Data Grows

SOQL design affects more than the raw number of queries and returned rows, but it is important to separate database execution time from Apex CPU time. Salesforce does not count the database’s own time spent executing SOQL or DML directly against the Apex CPU limit. Application-server work that prepares requests, evaluates surrounding automation, materializes results, iterates records, handles relationship data, or performs calculations can consume CPU. An inefficient or overly broad query can therefore contribute to a slow and resource-heavy transaction without supporting the simple claim that a database scan itself burns Apex CPU milliseconds.

A selective query uses filters that let Salesforce narrow the candidate records efficiently and return an appropriately small result set for the object’s size. Indexed fields can help, but the presence of an index alone does not guarantee selectivity. Salesforce also considers the cardinality of the filter and the execution plan. Standard indexed fields, lookup and master-detail fields, External ID fields, unique fields, and approved custom indexes can support selective access when the filter values reduce the search space enough to make the index useful.

The order in which conditions are written in a SOQL WHERE clause does not force Salesforce to evaluate them in that textual order. The query optimizer chooses an execution plan. Developers should therefore focus on selective indexed predicates, appropriate relationship filters, realistic data distribution, and only the fields and records the transaction needs. Leading-wildcard LIKE filters can prevent efficient index use, while a query with no meaningful filter can become expensive as the object grows. The Query Plan tool is useful when a query that once performed well starts operating against a much larger dataset.

Data growth can change the behavior of a query even when the Apex code has not changed. A filter that returns a small fraction of a 10,000-record object can have a very different cost profile when the object contains millions of rows or when the filtered value becomes much more common. Query performance should therefore be revisited as record counts, skew, automation, and business usage change. That review is especially valuable during Salesforce consulting and architecture reviews before large migrations, integrations, or new automation increase transaction volume around an existing query.

Monitoring Limits Before You Hit Them

Apex exposes runtime consumption for many important governor limits through the Limits class. Methods such as Limits.getQueries() and Limits.getLimitQueries() show current SOQL usage and the applicable ceiling for the transaction. Similar getter and limit methods exist for resources such as DML statements, CPU time, heap size, callouts, and other Apex limits. These methods make resource use observable in tests, debug instrumentation, and defensive design without waiting for a production transaction to cross a hard ceiling.

The strongest use of these methods is measurement, not last-second rescue logic. A shared utility method may enter a transaction after triggers, flows, package code, or other helpers have already consumed part of the same budget. Checking the remaining resource headroom can help with logging, diagnostics, controlled degradation where the business design supports it, or a decision made in advance to enqueue separate work. It should not become a generic pattern where any method close to a limit automatically moves arbitrary work asynchronously, because asynchronous boundaries affect transactionality, ordering, error handling, user expectations, and retry behavior.

A focused measurement pass can reveal problems that are difficult to infer from code inspection alone. Debug logs and targeted instrumentation can record query count, DML count, CPU consumption, heap use, callouts, and the points where major helper methods begin or end. Apex CPU time deserves separate attention because the database’s own query and DML execution time is excluded, while application-server processing around records and automation is included. Comparing resource use across realistic scenarios turns a vague “this transaction is heavy” diagnosis into evidence about which operation is consuming the budget and whether that consumption grows with record volume.

Testing for Governor Limits With Bulk Data

A trigger that is tested only with one or two records can pass every assertion and still fail under bulk execution. Salesforce can invoke an Apex trigger with up to 200 records in one trigger context, so tests should include bulk cases that exercise that boundary when the production path can receive bulk DML. This matters in custom Salesforce Service Cloud automation, where mass case updates, routing changes, or integration-driven writes can expose transaction patterns that single-record tests miss. The purpose is not to prove that a 200-record unit test reproduces every production condition. It is to verify that code designed for a bulk entry point remains bounded when that entry point is actually used.

A 200-record test is therefore an important boundary case rather than a guarantee of production behavior. Real orgs can add flows, validation rules, managed packages, data skew, sharing calculations, and larger related datasets that change the resource profile. Tests should also cover the record states that produce the heaviest branches of logic, including recursive paths and update scenarios where several automation layers run together. For packaged extensions and Salesforce AppExchange solutions, tests should account for the fact that customer orgs can have automation and data distributions that differ from the development environment.

A useful test class creates the required data, isolates the operation being measured with Test.startTest() and Test.stopTest() where appropriate, performs a bulk insert or update in one DML statement, and asserts the business outcome. Resource assertions should be tied to a defined budget rather than assuming one fixed query count is always correct. Teams that hire Salesforce developers for custom work should make this bulk-safety requirement part of review and acceptance criteria. A strong test can compare small and bulk inputs or verify that query and DML consumption remains bounded instead of increasing in direct proportion to every record. The result is a test that checks both functional correctness and the design property that protects the transaction under volume.

Common Mistakes When Designing Around Limits

Several limit problems appear repeatedly even in teams that understand the basic idea of bulkification. They usually come from treating one mitigation as universal or from looking at one class in isolation instead of the full transaction. These mistakes are worth keeping visible during code review because each can turn otherwise reasonable Apex into a production-only failure:

●   Assuming asynchronous limits are effectively unlimited and placing record-by-record queries, DML, or oversized in-memory processing inside a Queueable or Batch job

●   Wrapping code that exceeds a hard governor limit in try-catch and expecting System.LimitException to be recovered inside the same transaction

●   Testing only one or two records and never exercising the 200-record trigger context or other realistic bulk and recursion paths

●   Calling shared utilities from several automation paths without accounting for governor limits already consumed by earlier work in the same transaction

●   Reducing a Batch Apex scope immediately without first measuring whether the failure comes from avoidable inefficiency or from legitimate per-record resource cost

Batch scope illustrates why the remedy has to match the cause. Moving from a scope of 200 to 50 creates more execute transactions for the same number of records, which adds scheduling and transaction overhead. That can still be the right choice when each record carries unavoidable CPU, heap, callout, or downstream-processing cost. The disciplined approach is to optimize waste first, measure resource use per scope, and then choose a scope that leaves safe headroom while meeting the job’s throughput and operational requirements.

Callouts, Email, and Other Limits Worth Knowing

Several limits outside the core SOQL, DML, CPU, and heap group are especially important for integrations and notification logic. They may not appear in every transaction, but when they do, the same design principle applies: count the work across the whole transaction rather than evaluating each call in isolation. The table below keeps the limits that most often affect callout-heavy and message-heavy Apex designs in one place.

LimitValue
Callouts per transaction100
Combined callout timeout per transaction120 seconds
Future method invocations from a synchronous transaction50
Messaging.sendEmail method invocations per transaction10
Maximum Apex transaction execution time10 minutes

Callout timeout is cumulative across all callouts in the transaction. A design that makes three sequential external requests taking about 45 seconds each would exceed the 120-second cumulative ceiling even though no single request used the full amount. The transaction also has a separate limit of 100 callouts. Integration code should therefore consider the number of endpoints, expected response time, retries, and whether the user-facing transaction should wait for the external system at all. For API-heavy estates, MuleSoft integration services can move orchestration and transformation concerns away from record-by-record Apex callout patterns. Queueable Apex or another asynchronous integration pattern can also separate work when the business process does not require an immediate response.

The email limit in the table refers to Messaging.sendEmail method invocations per transaction, not simply to ten individual email messages. Code that invokes sendEmail once for every record can reach the method-call limit quickly during bulk processing. Grouping messages into fewer invocations where the messaging requirements allow it can reduce that pressure. Moving the work to another transaction can also separate it from the original transaction’s budget, but asynchronous execution does not make the per-transaction sendEmail invocation limit disappear, so the notification design still needs to be bulk-aware.

These secondary limits are easiest to manage when they are reviewed during design instead of after a failed integration or bulk update. A short transaction-budget check can identify whether callouts, future invocations, queued jobs, email method calls, or total execution duration are likely to become the controlling constraint. When custom APIs or middleware flows are being built through MuleSoft development services, the same review should cover retry behavior, payload size, and transaction boundaries on both sides of the integration. That keeps the solution focused on the resource that actually governs the workload instead of applying the same bulkification fix to every type of limit.

FAQs

Are Apex Governor Limits Applied Per User, Per Org, or Per Transaction?
Most hard Apex governor limits apply to one transaction. Salesforce also has separate org-level and daily allocations, so those should not be confused with per-transaction limits.

When Do Apex Governor Limits Reset?
Limits reset when a new transaction starts. Queueable jobs and Batch Apex execute chunks receive their own applicable limits, while code that remains inside the same transaction continues sharing the existing budget.

Does Test start Test Reset Governor Limits in Apex Tests?
Yes. Test start Test creates an isolated limit context for the code under test, and Test stop Test completes queued asynchronous work before the test resumes.

Does Scheduled Apex Use Asynchronous Governor Limits?
Scheduled Apex is asynchronous as a scheduling feature, but its scheduled execution uses synchronous Apex limits. Batch or Queueable work launched from it runs in separate transactions.

Can Queueable Apex Prevent a Too Many SOQL Queries Error?
Queueable Apex has a higher SOQL allowance than synchronous Apex, but inefficient code can still fail. Queries inside record-by-record loops can consume that budget quickly.

Do Flow and Apex Share the Same Governor Limits?
They can. When Flow and Apex run in the same transaction, their resource use shares that transaction’s budget. A true asynchronous boundary creates a separate transaction.

How Should a Trigger Be Tested for Governor Limit Safety?
Use a 200-record trigger test, realistic related automation, and assertions for the business result. The Limits class can also help measure queries, DML, CPU, and heap use.

Is One Trigger Per Object Required by Salesforce?
No. It is a common architecture pattern rather than a platform requirement. Teams use it to centralize trigger orchestration and make execution behavior easier to review and maintain.

Is a Static Boolean the Best Way to Stop Trigger Recursion?
Not always. Field-change checks, idempotent logic, or tracking processed record IDs can be safer when legitimate re-entry or multiple record groups must be handled.

Does an Indexed SOQL Filter Automatically Make a Query Selective?
No. Salesforce also considers expected result size and data distribution. For large objects, developers should review selectivity and inspect the query plan instead of relying on indexing alone.


Can the Limits Class Stop a Governor Limit Exception?
No. Limits methods report current consumption and the applicable ceiling. They help with diagnostics and design decisions, but they do not increase or bypass a hard governor limit.

When Is Batch Apex Better Than Queueable Apex?
  Batch Apex suits very large datasets that need separate execute transactions and fresh limits per chunk. Queueable Apex is usually better for smaller asynchronous jobs and chaining.

Is Reducing Batch Size Always the Wrong Fix for a Limit Error?
No. A smaller scope can be valid when measured CPU, heap, or callout cost requires it. Teams should still remove avoidable inefficiency first.

What Happens to Database Changes After System Limit Exception?
A hard governor-limit failure stops the transaction and rolls back its uncommitted database work. Because System Limit Exception cannot be recovered with an ordinary try-catch, prevention must happen before the limit is crossed.

What Are the Winter ’27 Apex Heap Limits?
In orgs upgraded to Winter ’27, Salesforce raises synchronous heap to 10 MB and asynchronous heap to 25 MB. Limits get Limit Heap Size shows the active limit for the current context.

By

Leave a Reply

Your email address will not be published. Required fields are marked *