Skip to main content

SF-0391 · Scenario · Medium

How can we schedule a batch apex?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

Two methods, depending on whether you want a recurring schedule or a one-shot run after a delay:

GoalUse
Recurring schedule (every day at 2 AM, every hour, etc.)System.schedule + a Schedulable wrapper class
Run a batch once after N minutesSystem.scheduleBatch

Recurring: wrap in Schedulable and use System.schedule

// 1. The batch itself
public class NightlyCleanupBatch implements Database.Batchable<sObject> {
    public Database.QueryLocator start(Database.BatchableContext ctx) {
        return Database.getQueryLocator(
            'SELECT Id FROM Case WHERE Status = \'New\' ' +
            'AND CreatedDate < LAST_N_DAYS:30'
        );
    }
    public void execute(Database.BatchableContext ctx, List<Case> scope) {
        for (Case c : scope) c.Status = 'Auto-Closed';
        update scope;
    }
    public void finish(Database.BatchableContext ctx) {}
}

// 2. The schedulable wrapper
public class ScheduleNightlyCleanup implements Schedulable {
    public void execute(SchedulableContext ctx) {
        Database.executeBatch(new NightlyCleanupBatch(), 200);
    }
}

// 3. Schedule it — runs at 2 AM every day
System.schedule(
    'Nightly Case Cleanup',
    '0 0 2 * * ?',
    new ScheduleNightlyCleanup()
);

The '0 0 2 * * ?' is a cron expression — see the related questions on CRON_EXP.

One-shot: System.scheduleBatch

If you just want a batch to run once, N minutes from now:

// Run MyBatch in 30 minutes, with chunk size 200
Id jobId = System.scheduleBatch(new MyBatch(), 'Retry MyBatch', 30, 200);

Signature: scheduleBatch(batchable, jobName, intervalInMinutes, scopeSize). Salesforce creates a Schedulable wrapper for you and schedules it to fire once.

Useful for retries — if Database.executeBatch failed because the queue was full, schedule a retry for a few minutes later.

Scheduling pattern matrix

You want…Use
Every day at 2 AMSystem.schedule + Schedulable + '0 0 2 * * ?'
Every hourSystem.schedule + Schedulable + '0 0 * * * ?'
Once, 30 min from nowSystem.scheduleBatch
Multiple recurring batchesMultiple System.schedule calls, distinct job names

The Schedulable wrapper is mandatory for System.schedule

System.schedule requires a Schedulable, not a Database.Batchable. The wrapper is one line — but you must include it. You can also fold the wrapper into the batch class itself:

public class NightlyCleanupBatch implements
    Database.Batchable<sObject>,
    Schedulable
{
    public void execute(SchedulableContext ctx) {
        Database.executeBatch(this, 200);
    }
    // ... start, execute(BatchableContext, scope), finish ...
}

One class doing double duty: it’s both schedulable and batchable. Then:

System.schedule('Nightly', '0 0 2 * * ?', new NightlyCleanupBatch());

Note the two execute methods — Apex distinguishes them by parameter type.

Avoid: scheduling Apex during deploys

Salesforce blocks code changes to a class that’s actively scheduled. If NightlyCleanupBatch is scheduled, you can’t deploy a new version. Workaround: abort the scheduled job, deploy, re-schedule.

Common interview follow-ups

  • Max scheduled jobs in an org? — 100 active Schedulable jobs.
  • Can the scheduled batch’s execute time exceed the next scheduled run? — Yes. They overlap. Watch the Flex Queue.
  • Does scheduleBatch count against the 100-active limit? — Yes, while it’s pending. Once it runs, the slot is freed.

Verified against: Apex Developer Guide — Using Batch Apex (Scheduling). Last reviewed 2026-05-17.