Cron vs setInterval in Node.js — Which Should You Use?

When you need to run code on a schedule in Node.js you have two main options: JavaScript's built-in setInterval or a cron-based library like node-cron. Both work, but they solve different problems. Picking the wrong one leads to subtle bugs around drift, missed runs, and time zone handling.

setInterval — the quick option

setInterval runs a function every N milliseconds from the moment it is called. It does not know about wall-clock time.

// Run every 5 minutes
setInterval(() => {
  console.log('tick:', new Date().toISOString());
  doWork();
}, 5 * 60 * 1000);

Pros: zero dependencies, simple, good for fixed intervals.
Cons: drifts over time (each callback adds a tiny delay), restarts reset the clock, can't express "every Monday at 9 AM", no timezone awareness.

node-cron — wall-clock scheduling

node-cron fires tasks at exact calendar times using cron expressions.

import cron from 'node-cron';

// Every weekday at 9:00 AM in Asia/Kolkata timezone
cron.schedule('0 9 * * 1-5', () => {
  console.log('Morning job running:', new Date().toISOString());
  doWork();
}, {
  timezone: 'Asia/Kolkata'
});

Pros: expressive schedules, timezone support, survives daylight saving changes, aligns to wall-clock minutes.
Cons: adds a dependency, slightly more setup.

The cron package (alternative)

The cron npm package offers a similar API with CronJob objects that can be started and stopped programmatically:

import { CronJob } from 'cron';

const job = new CronJob(
  '0 0 * * 0',            // every Sunday at midnight
  () => { weeklyReport(); },
  null,                   // onComplete
  true,                   // start immediately
  'Asia/Kolkata'
);

// Stop after first run
job.stop();

Decision guide

  • Use setInterval for simple, interval-based tasks where exact wall-clock time does not matter (e.g., polling an API every 30 seconds).
  • Use node-cron or cron when the task must run at a specific time of day, day of week, or on a calendar-based schedule.
  • Use an external scheduler (GitHub Actions, AWS EventBridge, Render cron jobs) when your Node.js server may restart or scale to multiple instances — you don't want duplicate job runs.

Handling overlapping runs

If your task takes longer than the schedule interval, you can end up with overlapping executions. Use a simple flag to prevent this:

let running = false;

cron.schedule('*/5 * * * *', async () => {
  if (running) return; // skip if previous run hasn't finished
  running = true;
  try {
    await doWork();
  } finally {
    running = false;
  }
});

Build your cron expression

Use the Dev Brains AI Cron Expression Generator to convert plain English like "every 5 minutes" or "every weekday at 9am" into the correct cron string for node-cron.