Scheduling Options ​
A bare cron.schedule(expression, task) already covers the common case. As your jobs grow more demanding, the optional third argument lets you tune how they run, without changing the rest of your code.
cron.schedule(expression, task, options);All options ​
export type Options = {
name?: string;
timezone?: string;
noOverlap?: boolean;
maxExecutions?: number;
maxRandomDelay?: number;
logger?: Logger;
suppressMissedWarning?: boolean;
missedExecutionTolerance?: number;
distributed?: boolean; // run on one instance per fire across a fleet
runCoordinator?: RunCoordinator; // per-task coordinator (overrides the global one)
distributedLease?: number; // lease ms for lease-based coordinators (default 30000)
executeTimeout?: number; // background tasks only
startTimeout?: number; // background tasks only
};| Option | Type | Default | Description |
|---|---|---|---|
name | string | task id | A human-readable identifier for the task. Useful for logging, debugging, and dashboards. |
timezone | string | system | The timezone the cron expression is evaluated in. Any IANA name recognized by Intl.DateTimeFormat (e.g. "America/Sao_Paulo", "UTC", "Europe/London"). See Timezones & DST for behavior across daylight-saving transitions. |
noOverlap | boolean | false | If true, a scheduled run is skipped when the previous run is still executing, preventing overlapping executions. |
maxExecutions | number | none | Maximum number of times the task may run. After the limit, the task is automatically destroyed. |
maxRandomDelay | number | 0 | Adds up to this many milliseconds of random delay (jitter) before each run. Spreads out tasks that would otherwise fire simultaneously. |
logger | Logger | global | A custom logger for this task, overriding the global one. Not supported for background tasks. |
suppressMissedWarning | boolean | false | Silences the "missed execution" warning for this task. See Logging. |
missedExecutionTolerance | number | 1000 | How late (in ms) a scheduled run may wake and still execute instead of being reported as missed. Long timers drift (OS sleep, GC, throttling, clock skew), which can otherwise skip daily/weekly runs. Always capped to the gap to the next run, so it can never run a slot twice. |
distributed | boolean | false | Run this task on a single instance per fire across a fleet. Requires a name. Uses the NODE_CRON_RUN env-var default (one designated runner) unless a coordinator is set. See Distributed Coordination. |
runCoordinator | RunCoordinator | global | A per-task run coordinator, overriding the one set with setRunCoordinator. Only used when distributed is true. |
distributedLease | number | 30000 | Lease expiry (ms) passed to lease-based coordinators (e.g. a Redis lock) in case the holder crashes mid-run. Must exceed the run time (and, when combined with maxRandomDelay, the jitter too, the lease is taken before the jitter). See Distributed Coordination. Ignored by the env-var default. |
🛈 There is no
scheduledorrunOnInitoption anymore. Tasks created withcron.schedulestart immediately; for a task that starts stopped, usecron.createTask. To run a task immediately on demand, calltask.execute(). See Migrating from v3.
Examples ​
Default options ​
import cron from 'node-cron';
const task = cron.schedule('* * * * *', () => {
console.log('Running every minute');
});Runs immediately on creation, in the system timezone, with overlapping runs allowed and no execution limit.
Custom timezone ​
Evaluate the expression in a specific timezone, regardless of where the server runs:
import cron from 'node-cron';
const task = cron.schedule('0 0 * * *', () => {
console.log('Midnight in São Paulo');
}, {
timezone: 'America/Sao_Paulo',
});Prevent overlapping runs ​
If a task can take longer than its interval, noOverlap skips a run rather than starting it on top of the previous one:
import cron from 'node-cron';
const task = cron.schedule('* * * * *', async () => {
await slowJob(); // may take longer than a minute
}, {
noOverlap: true,
});A skipped run emits an execution:overlap event.
Limit the number of runs ​
The task destroys itself after the limit is reached:
import cron from 'node-cron';
const task = cron.schedule('* * * * *', () => {
console.log('This runs 5 times, then the task is destroyed');
}, {
maxExecutions: 5,
});Reaching the limit emits execution:maxReached. For a one-shot task, set maxExecutions: 1.
Add jitter to avoid a thundering herd ​
When many instances schedule the same job at the same instant (e.g. across a fleet), maxRandomDelay staggers them:
import cron from 'node-cron';
const task = cron.schedule('0 * * * *', () => {
refreshCache();
}, {
maxRandomDelay: 30_000, // up to 30s of random delay per run
});Run on one instance across a fleet ​
When several copies of your app run the same schedule, distributed makes a task fire on only one instance per scheduled time. Out of the box you designate the runner with the NODE_CRON_RUN env var; for high availability, register a run coordinator (e.g. Redis):
import cron from 'node-cron';
cron.schedule('0 3 * * *', runNightlyBackup, {
name: 'nightly-backup', // required: forms the coordination key
distributed: true,
});A not-elected instance emits execution:skipped instead of running. See Distributed Coordination for the full picture.
Name a task ​
A name makes logs and dashboards readable, and is exposed as task.name:
import cron from 'node-cron';
const task = cron.schedule('0 3 * * *', () => {}, {
name: 'nightly-backup',
});
console.log(task.name); // 'nightly-backup'Tolerate late executions ​
A heartbeat is armed to fire at the scheduled time, but long timers drift (OS sleep, GC, CPU throttling, clock skew), so the callback can wake a little late. By default a run that wakes within missedExecutionTolerance (1000ms) still executes; later than that, it is reported as missed. On an underpowered host, or a daily/weekly job that can wake several seconds late, raise it:
import cron from 'node-cron';
const task = cron.schedule('0 3 * * 0', runWeeklyBackup, {
missedExecutionTolerance: 5 * 60_000, // still run if we wake up to 5 min late
});The tolerance is always capped to the gap until the next run, so it can never run the same slot twice. A late run fires once and the next slot is scheduled normally.
🛈 Background tasks accept two extra options,
executeTimeoutandstartTimeout, covered in Background Tasks.
Next steps ​
- Events & Observability: hook into overlap, missed runs, failures, and more.
- Logging: route node-cron's output through your own logger.