Job scheduling for Node.js with overlap prevention, distributed coordination, and background tasks. Schedule recurring tasks with cron expressions, prevent overlapping runs, coordinate across multiple instances, and run heavy jobs in isolated background processes. Zero dependencies, written in TypeScript.
npm install node-cron
import cron from 'node-cron';
cron.schedule('* * * * *', () => {
console.log('running a task every minute');
});
Long-running tasks can overlap when the next tick fires before the previous run finishes. noOverlap skips a run instead of stacking them:
cron.schedule('* * * * *', async () => {
await slowJob();
}, { noOverlap: true });
Running multiple instances of your app? distributed: true ensures only one instance executes each scheduled fire. Out of the box it uses an env-var flag; for high availability, plug in a Redis coordinator:
cron.schedule('0 3 * * *', runNightlyBackup, {
name: 'nightly-backup',
distributed: true,
});
Pass a file path instead of a function to run a job in an isolated forked process, so heavy work never blocks your event loop:
cron.schedule('0 3 * * *', './tasks/backup.js');
Every task exposes a single consistent interface for control and inspection:
const task = cron.schedule('0 3 * * *', doWork, {
name: 'nightly-backup',
timezone: 'America/Sao_Paulo',
});
task.stop(); // pause
task.start(); // resume
task.destroy(); // remove permanently
task.getStatus(); // 'stopped' | 'idle' | 'running' | 'destroyed'
task.getNextRun(); // next scheduled Date, or null
task.lastRun(); // { date, result } or { date, error }, or null
Tasks emit lifecycle events for observability:
task.on('execution:finished', (ctx) => console.log('result:', ctx.execution?.result));
task.on('execution:failed', (ctx) => console.error('failed:', ctx.execution?.error));
task.on('execution:overlap', () => console.warn('skipped: previous run still active'));
task.on('execution:skipped', (ctx) => console.log('not elected:', ctx.reason));
All events: task:started, task:stopped, task:destroyed, execution:started, execution:finished, execution:failed, execution:missed, execution:overlap, execution:maxReached, execution:skipped. See Events & Observability.
# ┌────────────── second (optional)
# │ ┌──────────── minute
# │ │ ┌────────── hour
# │ │ │ ┌──────── day of month
# │ │ │ │ ┌────── month
# │ │ │ │ │ ┌──── day of week
# │ │ │ │ │ │
# * * * * * *
| field | value |
|---|---|
| second | 0-59 (optional) |
| minute | 0-59 |
| hour | 0-23 |
| day of month | 1-31 (or L for the last day) |
| month | 1-12 (or names) |
| day of week | 0-7 (or names, 0 or 7 are Sunday; 2#3, 5L) |
Supports ranges (1-5), steps (*/2), lists (1,15), named months/weekdays, L (last day of month), # (nth weekday), and <weekday>L (last weekday of month). See the Cron Syntax guide.
cron.schedule('0 3 * * *', task, {
name: 'nightly-backup',
timezone: 'America/Sao_Paulo',
noOverlap: true,
distributed: true,
maxExecutions: 10,
maxRandomDelay: 30000,
});
See Scheduling Options for the full list.
v4 is a TypeScript rewrite with a smarter scheduler and a streamlined API. See the Migration Guide.
Feel free to submit issues and enhancement requests here.
In general, we follow the "fork-and-pull" Git workflow.
NOTE: Be sure to merge the latest from "upstream" before making a pull request!
Please do not contribute code you did not write yourself, unless you are certain you have the legal ability to do so. Also ensure all contributed code can be distributed under the ISC License.
node-cron is under ISC License.
$ claude mcp add node-cron \
-- python -m otcore.mcp_server <graph>