Home › Cron Jobs with Node.js
Cron Jobs with Node.js
Two approaches: run a Node script from crontab, or use node-cron to schedule jobs inside your application. Both have valid use cases.
Option 1: Run a Node Script from Crontab
The simplest approach. The OS cron daemon runs your Node script at the scheduled time. No library needed, no long-running process required.
0 2 * * * /usr/bin/node /home/user/scripts/backup.js >> /var/log/backup.log 2>&1
Use the full path to Node (which node to find it).
If you use nvm, the path changes per version - use ~/.nvm/versions/node/v20.x.x/bin/node or create a symlink.
nvm and cron do not get along
nvm sets up Node paths in your shell profile (.bashrc, .zshrc).
Cron does not load those files, so node is not on the PATH.
The fix: use the full path to the Node binary, or install Node globally with a package manager like apt or brew so it lives at a fixed path like /usr/bin/node.
Option 2: node-cron (In-Process Scheduling)
node-cron runs inside your Node.js application process. The schedule is defined in code, using standard 5-field cron syntax. Good when your job needs access to your app's database connections, shared state or other in-process resources.
npm install node-cron
Basic usage:
const cron = require('node-cron');
cron.schedule('0 2 * * *', () => {
console.log('Running daily backup at 2 AM');
// your task here
});
// With timezone
cron.schedule('0 9 * * 1-5', () => {
sendWeeklyReport();
}, {
timezone: 'Europe/Madrid'
});
With TypeScript:
import * as cron from 'node-cron';
cron.schedule('*/5 * * * *', (): void => {
processQueue();
});
node-cron vs node-schedule vs cron
| Library | Syntax | Seconds support | Timezone | Best for |
|---|---|---|---|---|
| node-cron | 5-field + optional seconds | Yes (6-field) | Yes | Simple recurring tasks |
| node-schedule | Cron strings or JS objects | Yes | Yes | Complex schedules, one-time jobs |
| cron (kelektiv) | 6-field (seconds first) | Yes (always) | Yes | Production apps, robust error handling |
Things to Watch Out For
In-process jobs die with the process
If your Node app crashes, restarts or is redeployed, the scheduled jobs stop.
Use a process manager like PM2 with pm2 start app.js to keep the app running.
For jobs that must survive app restarts, the OS crontab approach is more reliable.
6-field vs 5-field syntax
node-cron supports an optional seconds field as the first field, giving 6 fields total.
'*/10 * * * * *' means every 10 seconds.
'0 * * * * *' means every minute at second 0.
If your expression has 6 fields and does not behave as expected, check whether seconds are being interpreted.
Multiple instances running the same job
If you run multiple Node instances (load balancer, PM2 cluster mode), each one will fire the same scheduled job. Use a distributed lock (Redis, database) or designate one instance as the scheduler.
Async tasks need await
node-cron fires the callback synchronously. If your task is async, make the callback async:
cron.schedule('...', async () => { await myAsyncTask(); }).
Unhandled promise rejections inside cron callbacks will crash your app in newer Node versions.
Build your cron expression
node-cron uses the same 5-field cron syntax as Linux. Use the generator, copy the expression directly into your cron.schedule() call.