Governor Limits & Best Practices - Mastering Salesforce Development
Understanding and adhering to Salesforce Governor Limits is crucial for writing scalable, efficient, and deployable Apex code. This module will explain what governor limits are, why they exist, and how to write code that respects them.
1. Introduction to Governor Limits
Salesforce operates on a multi-tenant architecture, meaning that a single instance of the software serves multiple customers (tenants). To ensure that no single customer monopolizes the shared resources (like CPU, memory, database, network), Salesforce enforces strict runtime limits on Apex code and other platform features. These are known as Governor Limits.
Why do Governor Limits Exist?
- Resource Sharing: Prevents any single organization from consuming all available resources, ensuring fair usage for all tenants on the shared infrastructure.
- Scalability & Stability: Helps maintain the overall performance, stability, and reliability of the Salesforce platform for everyone.
- Code Efficiency: Encourages developers to write efficient, bulkified, and optimized code. It forces good programming practices.
- Security: Limits the potential impact of malicious or poorly written code.
Understanding these limits is not just about avoiding errors; it's about writing high-quality, performant, and scalable applications on the Salesforce platform. Failing to adhere to governor limits will result in runtime exceptions that halt your code execution.
2. Types of Governor Limits
Salesforce imposes various types of governor limits, each targeting different aspects of code execution and resource consumption. It's important to be aware of the most common ones:
a. Per-Transaction Apex Limits:
These limits apply to a single Apex transaction. A transaction starts when a trigger fires, an anonymous block executes, a web service call is made, etc., and ends when all associated DML, SOQL, and other operations are complete.
- SOQL Queries:
- Total number of SOQL queries issued: 100 (synchronous), 200 (asynchronous)
- Total number of records retrieved by SOQL queries: 50,000
- SOSL Queries:
- Total number of SOSL queries issued: 20
- DML Operations:
- Total number of DML statements issued: 150
- Total number of records processed by DML statements: 10,000
- CPU Time:
- Total CPU time for all Apex transactions: 10,000 ms (synchronous), 60,000 ms (asynchronous)
- Heap Size:
- Maximum heap size (memory used by your Apex code): 6 MB (synchronous), 12 MB (asynchronous)
- Callouts:
- Total number of callouts (HTTP requests or web services calls): 100
- Maximum cumulative timeout for all callouts: 120 seconds
- Circumference of Loops:
- Total number of records retrieved by `Database.getQueryLocator`: 50,000,000 (for Batch Apex)
- Future Methods:
- Total number of `@future` method calls per transaction: 50
- Queueable Jobs:
- Maximum number of Queueable jobs added to the queue in a single transaction: 50
b. Per-Organization Limits:
These limits apply across your entire Salesforce organization, not just a single transaction.
- Scheduled Jobs: Maximum number of scheduled jobs: 100
- Batch Apex Jobs: Maximum number of Batch Apex jobs queued or active at one time: 5
- Daily Async Apex Executions: Total number of asynchronous Apex method executions (future, Queueable, batch, scheduled) per 24 hours: Varies by org edition (e.g., 250,000 or more, plus 200 * number of user licenses).
c. Other Important Limits:
- Maximum trigger depth: 16 (prevents infinite recursion)
- Maximum stack depth: 1,000 (prevents infinite recursion in method calls)
- Maximum number of Apex classes/triggers: 5 MB of compiled Apex code.
For the most up-to-date and complete list of governor limits, always refer to the official Salesforce Apex Developer Guide: Governor Limits.
3. Common Governor Limit Errors
When governor limits are exceeded, Salesforce throws runtime exceptions that stop your code execution. Understanding these errors will help you diagnose and fix problems quickly:
- System.LimitException: Too many SOQL queries: Occurs when the code executes more than 100 SOQL queries in a synchronous transaction.
- System.LimitException: Too many DML statements: Happens if more than 150 DML operations are performed in one transaction.
- System.LimitException: Apex CPU time limit exceeded: Apex code has run longer than 10 seconds synchronously or 60 seconds asynchronously.
- System.LimitException: Heap size too large: The Apex heap size exceeds 6 MB (synchronous) or 12 MB (asynchronous).
- System.LimitException: Too many callouts: More than 100 callouts or 120 seconds of cumulative callout time in a transaction.
Recognizing these exceptions early helps avoid costly debugging and improves code performance and reliability.
4. Strategies & Best Practices
Writing governor-limit-aware Apex requires following best practices to keep your code efficient, maintainable, and scalable:
- Bulkify Your Code: Always design code to handle multiple records at once, avoiding SOQL and DML inside loops.
- Use Collections Wisely: Use lists, maps, and sets to reduce queries and DML operations.
- Avoid Recursive Triggers: Prevent infinite loops by using static flags or handler classes.
- Optimize SOQL Queries: Select only required fields, filter records with indexed fields, and avoid unnecessary queries.
- Use Asynchronous Processing: For complex or long-running tasks, leverage `@future`, Queueable, Batch Apex, or Scheduled Apex.
- Limit Data Returned: Use selective queries and pagination to limit heap usage and improve CPU time.
- Test with Large Data Volumes: Write tests that simulate bulk data to verify your code handles limits gracefully.
5. Testing for Governor Limits
Effective testing is essential to ensure your Apex code respects governor limits under real-world conditions:
- Use @TestSetup Methods: Create reusable test data to simulate bulk processing.
- Write Bulk Tests: Test triggers and classes with collections of records, not just single instances.
- Simulate Limit Exceptions: Use mocks or specialized code patterns to mimic limit exceptions and verify graceful handling.
- Measure Performance: Use debug logs to track CPU time, heap size, and query counts during test execution.
- Leverage Salesforce Tools: Use Developer Console, Apex Test Execution, and the Limits class to monitor resource usage.
- Continuous Integration: Integrate tests into CI/CD pipelines to catch limit-related issues early in the development cycle.
6. Conclusion & Key Takeaways
Understanding and proactively managing Salesforce Governor Limits is paramount for any developer working on the platform. They are not merely obstacles to overcome, but fundamental guardrails that ensure the stability, scalability, and fairness of a multi-tenant environment.
Key Takeaways:
- Multi-Tenancy is Key: Limits exist to protect shared resources and ensure optimal performance for all Salesforce customers.
- Bulkify Everything: This is the golden rule. Avoid SOQL queries and DML statements inside loops. Process data in collections.
- One Trigger, One Handler: Centralize your trigger logic for better maintainability and control over execution order.
- Go Async When Necessary: For long-running processes, external callouts, or large data transformations, leverage `@future`, Queueable, Batch, or Scheduled Apex.
- Be Selective: Write SOQL queries that efficiently use indexed fields to retrieve only the data you need.
- Guard Against Recursion: Implement static variables in trigger handlers to prevent infinite loops.
- Test Thoroughly: Always include unit tests that simulate maximum record scenarios to ensure your code handles governor limits gracefully.
By internalizing these best practices, you'll not only avoid hitting governor limits but also become a more skilled, confident, and effective Salesforce developer, capable of building high-quality, scalable solutions.