The scope parameter of Database.executeBatch accepts an integer between 1 and 2,000.
| Bound | Value |
|---|---|
| Minimum | 1 |
| Maximum | 2,000 |
| Default (no value passed) | 200 |
Below 1 or above 2,000, Salesforce throws System.InvalidValueException (or simply ignores the value, falling back to 200, depending on the call form).
How to set it
// Default: 200 per chunk
Database.executeBatch(new MyBatch());
// Custom: 50 per chunk
Database.executeBatch(new MyBatch(), 50);
// Max
Database.executeBatch(new MyBatch(), 2000);
What scope size actually controls
Each execute invocation receives a List<sObject> scope containing that many records. Each invocation is its own transaction with its own governor limits.
| Chunk size | Effect |
|---|---|
| 1 | One transaction per record. Highest overhead, safest for very heavy per-record logic. |
| 50 | Good for callout-heavy batches (callouts are limited per transaction). |
| 200 (default) | Standard balance — good for most jobs. |
| 1000 | Fewer transactions, bigger chunks. Risk of CPU/SOQL limit blowouts. |
| 2000 | Maximum efficiency, maximum risk. |
How to choose
| Situation | Suggested chunk size |
|---|---|
| Simple field updates, no triggers cascading | 200 |
| Triggers/flows that update related records | 50–100 |
| Each record triggers a callout | 10–25 (callouts limited to 100 per transaction) |
| Heavy CPU work per record (calc, parse) | 25–100 |
| Pure DML on cold records (no side effects) | 500–2000 |
| Hitting governor limits at 200 | Drop to 50 or 25 |
| Want to minimize total transactions | 2000 |
Why bigger isn’t always better
Each chunk runs in one transaction:
| Per-transaction limit | Value |
|---|---|
| SOQL queries | 100 |
| DML statements | 150 |
| DML rows | 10,000 |
| CPU time | 60,000 ms |
| Heap | 12 MB |
If your execute makes 1 SOQL per record and you set chunk size to 2,000, you hit the 100-SOQL limit on the 101st record. Always bulkify so the chunk runs in constant number of SOQL/DML regardless of size.
How chunking interacts with QueryLocator
Database.QueryLocator.start returns up to 50 million records. The platform pages through them in chunks of your scope size. So a 10 M record job with scope 200 spawns 50,000 chunks — each a separate transaction, separate governor limits.
Common interview follow-ups
- Default scope size? — 200.
- Maximum? — 2,000.
- Why is there a maximum at all? — Each chunk must fit within governor limits — 2,000 is the platform-determined ceiling for safe operation.
- Can I change scope mid-job? — No. It’s fixed at
executeBatchtime.
Verified against: Apex Developer Guide — Using Batch Apex. Last reviewed 2026-05-17.