Salesforce Governor Limits: Architectural Patterns for Scale Beyond 10,000 Records
Salesforce's 10,000-record DML limit forces architectural decisions. Batch Apex breaks work into chunks, but each pattern has its own governor constraints. Process 50,000 accounts safely with proper error handling and monitoring.
01 Jul 2025, 02:16 UTC

The Hard Stop: When 10,000 Records Isn't Enough
Salesforce's DML limit of 10,000 records per transaction is a non-negotiable boundary. When you need to process more than 10,000 records, you hit a DmlException: LimitException that crashes your transaction. This isn't a performance issue—it's a platform constraint that demands architectural rethinking.
Smallest Suitable Design: Batch Apex for Bulk Operations
Batch Apex is the canonical solution for processing large datasets. It breaks work into manageable chunks (default 200 records per batch) while respecting governor limits across each chunk. Unlike synchronous code, Batch Apex can process millions of records with built-in checkpointing and error handling.
Trust Boundaries: What Batch Apex Actually Isolates
Each batch execution runs in its own transaction context. This means:
- SOQL limits reset per batch (100,000 rows per batch, not total)
- DML limits apply to records in that specific batch scope
- Heap limits (6MB sync/12MB async) apply per batch transaction
- Sharing settings can be controlled with explicit
with sharingorwithout sharing
Operational Checks: Verifying Your Batch Works
Before deploying to production, validate these operational signals:
- Batch job size: Use
Database.QueryLocatorfor large datasets—automatically chunks queries over 50,000 records - Error handling: Implement
Database.AllowsCalloutsinterface for external API calls per batch - Monitoring: Check
AsyncApexJobrecords in Setup for success/failure rates - Governor limit exhaustion: Use
Limits.getDMLRows()and similar methods inside batch to log consumption
Concrete Example: Updating 50,000 Account Records
This pattern processes 50,000 accounts while respecting all governor limits:
public class AccountUpdater implements Database.Batchable, Database.Stateful {
public Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator([
SELECT Id, Industry FROM Account WHERE AnnualRevenue > 1000000
]);
}
public void execute(Database.BatchableContext bc, List accounts) {
// Process up to 200 records per batch (default batch size)
for (Account acc : accounts) {
acc.Rating = 'Hot';
}
Database.SaveResult[] results = Database.update(accounts, false);
// Log any errors
for (Integer i = 0; i < results.size(); i++) {
if (!results[i].isSuccess()) {
System.debug('Error updating Account ' + accounts[i].Id);
}
}
}
public void finish(Database.BatchableContext bc) {
// Optional: Send email or call external service
}
}
// Execute with:
// Database.executeBatch(new AccountUpdater(), 200);
Failure Modes: When Batch Apex Isn't Enough
Batch Apex has limits of its own:
- Daily concurrent job limit: 250 async jobs per org—high-volume orgs may queue jobs
- CPU time: 60 seconds for synchronous, 10 minutes for asynchronous—long-running logic must be chunked
- Heap size: 12MB in async context—accumulating large collections across batches causes
System.LimitException: Heap Size too large
Conditions That Change the Design
Consider these alternatives when Batch Apex doesn't fit:
| Scenario | Alternative Pattern | Why It Fits |
|---|---|---|
| Need to chain dependent operations | Queueable Apex | Allows job chaining with System.enqueueJob(), better than Future methods |
| Processing triggered by user action | Future methods with chunking | Simple fire-and-forget for smaller bulk operations |
| Cross-org data synchronization | Salesforce Integration Cloud or custom middleware | Bypasses org-level limits through external orchestration |
Verification Checklist
Run these checks before and after deployment:
- Developer Console Limits: Execute
System.runAs()and monitorLimits.getXXX()methods - Governor Limits Setup page: Review org-specific limits under Setup → System Overview
- Bulk API testing: For external integrations, test with Salesforce's Load Testing Tool
- Production monitoring: Query
SELECT Id, Status, NumberOfErrors FROM AsyncApexJob WHERE JobType='BatchApex'after deployment
Key Takeaway
Architect for chunking from day one. The 10,000-record DML limit is just the first boundary—you'll hit SOQL, heap, and concurrent job limits before you've processed your full dataset. Design patterns like Batch Apex aren't optimizations; they're the only way to operate at scale in Salesforce's multi-tenant environment.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.