Cron vs setTimeout vs External Schedulers Choosing the Right Scheduling Method
Compare different scheduling methods in Node.js node-cron, setTimeout, setInterval, PM2 cron, system cron, and external services like AWS EventBridge.
Cron vs setTimeout vs External Schedulers
Node.js offers multiple ways to schedule tasks. This guide compares them and helps you choose the right one.
1. setTimeout / setInterval (In-App)
// Run once after 5 seconds setTimeout(() => { console.log("One-time task"); }, 5000); // Run every 60 seconds setInterval(() => { console.log("Recurring task"); }, 60000);
Pros: Built-in, no dependencies, millisecond precision Cons: Lost on restart, drift over time, no complex schedules
Best for: Short intervals (< 1 minute), one-time delays, polling
2. node-cron (In-App)
const cron = require("node-cron"); cron.schedule("0 0 * * *", () => { console.log("Daily at midnight"); });
Pros: Cron expressions (complex schedules), in-app (access to models/cache), easy to use Cons: Lost on restart, single process (no distribution)
Best for: App-integrated tasks (cleanup, notifications, reports)
3. PM2 cron (Server-Level)
pm2 start script.js --cron "0 0 * * *"
Pros: Survives app crashes, PM2 managed (restart, logs), separate process Cons: Separate script (no app context), requires PM2
Best for: Independent tasks (backups, log rotation, system checks)
4. System cron (OS-Level)
# crontab -e 0 0 * * * /usr/bin/node /home/ubuntu/devtinder/scripts/backup.js
Pros: OS-level (survives everything), simple, no dependencies Cons: No PM2 management, limited logging, hard to monitor
Best for: Server maintenance, backups, simple scripts
5. AWS EventBridge (Cloud)
{ "EventBusName": "default", "ScheduleExpression": "cron(0 0 * * ? *)", "Targets": [{ "Arn": "arn:aws:lambda:us-east-1:123:function:devtinder-cleanup", "Input": "{}" }] }
Pros: Fully managed, survives everything, triggers Lambda/EC2/SQS, retry policies Cons: AWS-only, costs money, more complex setup
Best for: Serverless apps, multi-service orchestration, enterprise
6. Bull/BullMQ (Queue-Based)
const Queue = require("bull"); const emailQueue = new Queue("emails", { redis: { host: "127.0.0.1", port: 6379 } }); // Repeat job every day at midnight emailQueue.add("daily-digest", {}, { repeat: { cron: "0 0 * * *" } });
Pros: Distributed (multiple workers), persistent (Redis), retry, priority Cons: Requires Redis, more complex
Best for: Distributed systems, high-volume tasks, job queues
Comparison Table
| Method | Precision | Survives Restart | Distributed | Complexity | Best For |
|---|---|---|---|---|---|
| setTimeout | ms | No | No | Lowest | One-time delays |
| setInterval | ms | No | No | Low | Short intervals |
| node-cron | minute | No | No | Low | App tasks |
| PM2 cron | minute | Yes | No | Medium | Server tasks |
| System cron | minute | Yes | No | Low | OS tasks |
| EventBridge | minute | Yes | Yes | High | Serverless |
| Bull/BullMQ | second | Yes (Redis) | Yes | Medium | Distributed |
Decision Guide
Need to run something in 5 seconds?
→ setTimeout
Need to poll every 30 seconds?
→ setInterval
Need "every day at midnight" in your app?
→ node-cron
Need a backup script that survives app crashes?
→ PM2 cron
Need server maintenance tasks?
→ System cron
Running on AWS Lambda and need scheduled tasks?
→ AWS EventBridge
Need distributed job processing?
→ Bull/BullMQ
The Takeaway
Choose your scheduling method based on your needs: setTimeout/setInterval for short in-app intervals, node-cron for scheduled app tasks (cleanup, notifications), PM2 cron for independent server tasks (backups), system cron for OS-level maintenance, AWS EventBridge for serverless, and Bull/BullMQ for distributed job processing. Most Node.js apps use node-cron for app tasks and PM2 cron for backups.
Use setTimeout/setInterval for short intervals, node-cron for scheduled app tasks (cleanup, notifications, reports), PM2 cron for independent server tasks (backups, log rotation), system cron for OS-level maintenance, AWS EventBridge for serverless, and Bull/BullMQ for distributed job processing.
node-cron runs inside your app process (has access to models, cache, database connections) but is lost on restart. PM2 cron runs as separate scripts managed by PM2 (survives app crashes, has its own logs) but doesn't have app context. Use node-cron for app-integrated tasks, PM2 cron for independent tasks.
Use Bull/BullMQ when you need distributed job processing (multiple workers), persistence (survives restart via Redis), retry with backoff, priority queues, or rate limiting. Use cron for simpler scheduled tasks that don't need distribution or persistence.
EventBridge is a fully managed AWS service that can trigger Lambda functions, EC2, or SQS on a cron schedule. It survives everything, supports retry policies, and is ideal for serverless architectures. Use it when your app runs on AWS Lambda or needs multi-service orchestration.
setInterval uses milliseconds (not human-readable cron expressions), drifts over time (doesn't account for event loop delays), is lost on app restart, and can't express complex schedules like 'weekdays at 9 AM'. Use node-cron for anything more complex than a fixed interval.
Ready to master Node.js completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master Node.js
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

