Using PM2 cron-start for Recurring Tasks Server-Level Scheduling
Learn how to use PM2's cron-start feature to schedule Node.js scripts at the server level an alternative to node-cron for production deployments.
Using PM2 cron-start for Recurring Tasks
PM2 has built-in cron support that runs Node.js scripts at scheduled intervals. This is a server-level alternative to node-cron.
Why Use PM2 cron?
- Server-level Runs even if your main app is down
- PM2 managed Automatic restart on failure
- No extra dependencies Built into PM2
- Logs PM2 captures all output
- Simple No code changes needed
PM2 cron-start Syntax
# Run a script every day at midnight pm2 start scripts/cleanup.js --cron "0 0 * * *" --name daily-cleanup # Run every hour pm2 start scripts/stats.js --cron "0 * * * *" --name hourly-stats # Run every 15 minutes pm2 start scripts/health-check.js --cron "*/15 * * * *" --name health-check
PM2 Ecosystem File
// ecosystem.config.js module.exports = { apps: [ // Main API server { name: "devtinder-api", script: "src/server.js", instances: "max", exec_mode: "cluster" }, // Cron jobs { name: "daily-cleanup", script: "scripts/cleanup.js", cron: "0 0 * * *", autorestart: false // Don't restart after completion }, { name: "hourly-stats", script: "scripts/stats.js", cron: "0 * * * *", autorestart: false }, { name: "weekly-report", script: "scripts/weeklyReport.js", cron: "0 0 * * 1", // Every Monday at midnight autorestart: false } ] };
pm2 start ecosystem.config.js pm2 save
Creating Cron Scripts
// scripts/cleanup.js require("dotenv").config(); const mongoose = require("mongoose"); const User = require("../src/models/User"); const run = async () => { try { await mongoose.connect(process.env.MONGODB_URI); console.log("Connected to MongoDB"); // Delete expired tokens const result = await User.updateMany( { resetPasswordExpires: { $lt: new Date() } }, { $unset: { resetPasswordToken: 1, resetPasswordExpires: 1 } } ); console.log(`Cleaned up ${result.modifiedCount} users`); await mongoose.disconnect(); console.log("Done"); process.exit(0); } catch (err) { console.error("Cleanup failed:", err); process.exit(1); } }; run();
PM2 cron vs node-cron
| Feature | PM2 cron | node-cron |
|---|---|---|
| Runs in | Separate process | In the main app |
| Survives app crash | Yes | No |
| Logs | PM2 logs | App logs |
| Dependencies | PM2 only | node-cron package |
| Complexity | Separate script | Inline in app |
| Best for | Independent tasks | App-integrated tasks |
When to Use PM2 cron vs node-cron
Use PM2 cron for:
- Database backups (independent of app)
- Log rotation (server-level)
- System health checks
- Report generation (doesn't need app context)
Use node-cron for:
- Tasks that need app state (cache, connections)
- Tasks that use app models and utilities
- Tasks that should stop when the app stops
- Tasks that need the same database connection
Viewing PM2 Cron Jobs
# List all PM2 processes pm2 status # View logs of a specific cron job pm2 logs daily-cleanup # View logs of all cron jobs pm2 logs # Stop a cron job pm2 stop daily-cleanup # Restart a cron job pm2 restart daily-cleanup # Delete a cron job pm2 delete daily-cleanup
The Takeaway
PM2 cron-start runs Node.js scripts at scheduled intervals at the server level. Use it for independent tasks like backups, log rotation, and system health checks. Use node-cron for tasks integrated with your app (using models, cache, connections). Both use cron expressions. PM2 cron jobs are managed by PM2 (automatic restart, logs, monitoring) and run in separate processes.
Use pm2 start script.js --cron '0 0 * * *' --name task-name. Or define in ecosystem.config.js with cron: '0 0 * * *' and autorestart: false. PM2 runs the script at the scheduled time, captures logs, and manages restarts.
Use PM2 cron for independent tasks (backups, log rotation, system checks) that don't need app context. Use node-cron for tasks integrated with your app (using models, cache, database connections) that should stop when the app stops.
Create a standalone script that connects to the database, performs the task, and exits with process.exit(0) on success or process.exit(1) on failure. Load dotenv, connect to MongoDB, run the task, disconnect, and exit. PM2 will run it at the scheduled cron time.
Use pm2 logs task-name to view logs of a specific cron job. Use pm2 logs to view all logs. Use pm2 status to see all processes including cron jobs and their last execution status.
Yes. Cron jobs are one-time scripts that run and exit. Without autorestart: false, PM2 would restart the script immediately after it exits, causing it to run continuously instead of only at the scheduled cron time.
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.

