Salesforce Batch Apex: Processing Millions of Records Without Hitting Governor Limits
If you have ever tried to update 50,000 records with a Flow or a trigger and watched Salesforce stop you cold, you have met governor limits. Batch Apex exists for exactly this problem: it breaks a huge job into small, safe chunks and processes them one at a time.
How Batch Apex actually works
A batch job has three parts. The start method collects the records to process — usually with a SOQL query locator. The execute method runs once per chunk (the default scope is 200 records) and does the real work. The finish method runs once at the end, which is where you send a summary email or kick off the next job.
That chunking is the whole point. Each execute call gets its own fresh set of governor limits, so a job that would blow up as a single transaction sails through as a batch.
5 practices that keep batch jobs healthy
1. Keep the scope small on purpose. The default 200-record scope is fine for simple updates, but if each record triggers heavy logic — callouts, complex calculations, related-record updates — drop the scope to 50 or even 10. A slower job that finishes beats a fast one that fails halfway.
2. Make execute idempotent. A batch can be retried, and a chunk can occasionally run twice. Write your logic so running it again on the same records changes nothing the second time. Check-before-update beats blind updates every time.
3. Never put SOQL or DML inside a loop. This is the oldest Apex rule in the book and it matters most in batch jobs, because a single sloppy loop multiplied across thousands of chunks is how orgs hit limits at 2 AM. Collect, then act on the collection.
4. Handle errors per chunk, not per job. Wrap risky logic in try-catch inside execute and log failures to a custom object or send a digest in finish. One bad record should never kill a 100,000-record job — and you should be able to find the bad record afterwards.
5. Test with realistic volumes. A batch that passes its test class with 200 records can still fail in production with two million. Your test classes should cover the empty batch, the single-chunk batch, and the multi-chunk batch. That coverage discipline is what keeps batch code deployable — see our guide on Salesforce test classes and code coverage.
When Batch Apex is the wrong tool
Not every big job needs a batch. If the work is under 50,000 records and runs on a schedule, a scheduled Flow may be simpler. If it needs to happen the moment a record changes, a record-triggered Flow or Queueable Apex fits better. Batch Apex shines for nightly data cleanup, mass recalculations, and migrations — the jobs where volume is the problem, not timing.
And before any large-scale update, clean the data first. A batch job that faithfully processes dirty data just produces dirty results faster. Our write-up on why every AI strategy needs data cleaning first applies just as well to batch jobs: garbage in, garbage out, at scale.
The bottom line
Batch Apex is not glamorous, but it is the workhorse behind every Salesforce org that handles real data volumes. Small scopes, idempotent logic, no queries in loops, per-chunk error handling, and honest testing — get those five right and your batch jobs will quietly do their work while you sleep.
Originally published at Way2Force — practical guides on Salesforce Flow, automation, and CRM.
Top comments (0)