What are Cron Expressions?
Cron expressions are strings used to schedule tasks to run periodically at fixed times, dates, or intervals. Originally developed for Unix systems, cron expressions are now used across many platforms and scheduling systems.
// Basic cron expression format
* * * * * command_to_execute
│ │ │ │ └── Day of week (0-7, where 0 and 7 = Sunday)
│ │ │ └──── Month (1-12)
│ │ └────── Day of month (1-31)
│ └──────── Hour (0-23)
└────────── Minute (0-59)
Cron expressions provide a powerful way to automate repetitive tasks like backups, data processing, report generation, and system maintenance.
Cron Expression Syntax
Field Definitions
| Field |
Allowed Values |
Special Characters |
| Minute |
0-59 |
* , - / |
| Hour |
0-23 |
* , - / |
| Day of Month |
1-31 |
* , - / ? L W |
| Month |
1-12 or JAN-DEC |
* , - / |
| Day of Week |
0-7 or SUN-SAT (0/7 = Sunday) |
* , - / ? L # |
Special Characters
Basic Characters
- * (asterisk): Any value
- , (comma): Value list separator
- - (hyphen): Range of values
- / (slash): Step values
Advanced Characters
- ? (question): No specific value (day of month/week)
- L (last): Last day of month/week
- W (weekday): Nearest weekday
- # (hash): Nth day of month
Common Cron Patterns
Basic Scheduling
| Expression |
Description |
Example |
0 * * * * |
Every hour at minute 0 |
Hourly tasks |
0 0 * * * |
Daily at midnight |
Daily backups |
0 0 * * 0 |
Weekly on Sunday |
Weekly reports |
0 0 1 * * |
Monthly on 1st day |
Monthly billing |
*/15 * * * * |
Every 15 minutes |
Monitoring checks |
0 9-17 * * 1-5 |
Hourly on weekdays 9AM-5PM |
Business hours tasks |
Advanced Patterns
// Complex cron examples
// Every 10 minutes during business hours on weekdays
*/10 9-17 * * 1-5
// At 30 minutes past the hour every 6 hours
30 */6 * * *
// At 5:30 PM on the last day of every month
30 17 L * *
// At 9:00 AM on the 15th day of every month
0 9 15 * *
// Every Monday at 8:00 AM
0 8 * * 1
// Every day at 1:30 AM and 1:30 PM
30 1,13 * * *
// Every 5 minutes from 9 AM to 5 PM on weekdays
*/5 9-17 * * 1-5
// First Monday of every month at 10:00 AM
0 10 * * 1#1
Implementation Examples
1. Linux/Unix crontab
# Edit crontab
crontab -e
# Example crontab entries
# Backup database daily at 2:30 AM
30 2 * * * /usr/bin/mysqldump -u root -pPASSWORD database > /backups/db-$(date +\%Y\%m\%d).sql
# Clean temp files every Sunday at 3:00 AM
0 3 * * 0 rm -rf /tmp/*
# Monitor disk space every hour
0 * * * * /usr/local/bin/check-disk-space.sh
# Sync logs every 15 minutes
*/15 * * * * rsync -avz /var/log/ remote-server:/backups/logs/
# Send daily report at 6:00 PM
0 18 * * * /usr/local/bin/send-daily-report.sh
2. Node.js with node-cron
const cron = require('node-cron');
// Run every minute
cron.schedule('* * * * *', () => {
console.log('Running every minute');
});
// Run daily at midnight
cron.schedule('0 0 * * *', () => {
console.log('Running daily backup');
performBackup();
});
// Run every 30 minutes during business hours
cron.schedule('*/30 9-17 * * 1-5', () => {
console.log('Checking for new emails');
checkEmails();
});
// Run on specific days
cron.schedule('0 8 * * 1,3,5', () => {
console.log('Monday, Wednesday, Friday morning task');
generateReports();
});
// Complex: First day of month at 9 AM
cron.schedule('0 9 1 * *', () => {
console.log('Monthly billing process');
processBilling();
});
3. Python with schedule
import schedule
import time
def job():
print("I'm working...")
# Schedule examples
schedule.every(10).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at("10:30").do(job)
schedule.every().monday.do(job)
schedule.every().wednesday.at("13:15").do(job)
schedule.every().minute.at(":17").do(job)
# Cron-style scheduling with python-crontab
from crontab import CronTab
cron = CronTab(user=True)
job = cron.new(command='python /path/to/script.py')
job.setall('0 0 * * *') # Daily at midnight
cron.write()
Best Practices
Scheduling Best Practices:
- Stagger execution times: Avoid running all jobs at the same time (e.g., midnight)
- Consider timezones: Always specify timezone in cron configuration
- Log job execution: Log start, end, and any errors for debugging
- Implement job locking: Prevent overlapping job execution
- Monitor job health: Set up alerts for failed jobs
1. Error Handling and Monitoring
// Example: Robust cron job with error handling
const cron = require('node-cron');
const logger = require('./logger');
const { sendAlert } = require('./alerts');
cron.schedule('0 2 * * *', async () => {
const jobId = `backup-${Date.now()}`;
try {
logger.info(`Starting backup job: ${jobId}`);
// Perform backup
await performBackup();
logger.info(`Backup job completed: ${jobId}`);
} catch (error) {
logger.error(`Backup job failed: ${jobId}`, { error: error.message });
// Send alert
await sendAlert({
type: 'cron_failure',
job: 'daily_backup',
error: error.message,
timestamp: new Date().toISOString()
});
// Optionally retry
await retryBackup();
}
});
2. Job Locking (Prevent Overlaps)
// Using file-based locking
const fs = require('fs');
const path = require('path');
function withLock(jobName, fn) {
const lockFile = path.join('/tmp', `${jobName}.lock`);
// Check if lock exists
if (fs.existsSync(lockFile)) {
const lockTime = fs.statSync(lockFile).mtime;
const age = Date.now() - lockTime.getTime();
// If lock is older than 1 hour, assume stale and remove
if (age > 60 * 60 * 1000) {
fs.unlinkSync(lockFile);
} else {
console.log(`Job ${jobName} is already running`);
return;
}
}
// Create lock file
fs.writeFileSync(lockFile, process.pid.toString());
try {
// Execute job
return fn();
} finally {
// Remove lock file
fs.unlinkSync(lockFile);
}
}
// Usage
cron.schedule('*/5 * * * *', () => {
withLock('data-sync', () => {
syncData();
});
});
Common Pitfalls and Solutions
Common Issues:
- Timezone confusion: Cron uses system timezone
- Day of week vs day of month: Use
? for one when specifying the other
- February 30th: Cron will skip invalid dates
- Environment variables: Cron jobs run with minimal environment
- Permission issues: Cron runs as user who owns crontab
1. Environment Variables
# Bad: PATH may not include needed binaries
* * * * * some-command
# Good: Set PATH in crontab
PATH=/usr/local/bin:/usr/bin:/bin
# Better: Source environment or use full paths
* * * * * /usr/local/bin/my-script.sh
# Best: Create wrapper script that sets environment
* * * * * /path/to/wrapper.sh
2. Logging and Output
# Bad: No logging, errors go to email (may be ignored)
* * * * * /path/to/script.sh
# Good: Redirect output to log file
* * * * * /path/to/script.sh >> /var/log/script.log 2>&1
# Better: Separate stdout and stderr
* * * * * /path/to/script.sh >> /var/log/script.log 2>> /var/log/script.error.log
# Best: Use logger command for syslog
* * * * * /path/to/script.sh 2>&1 | logger -t myscript
Tools and Resources
DailyTools.uk Cron Tool
Use our Cron Expression Parser Tool to:
- Parse and validate cron expressions
- Get human-readable explanations
- Test scheduling patterns
- Generate cron expressions from natural language
External Resources
Conclusion
Cron expressions are a powerful tool for automating repetitive tasks, but they require careful implementation to avoid common pitfalls. Key takeaways:
Essential Practices:
- Always validate cron expressions before deployment
- Implement proper logging and error handling
- Use job locking to prevent overlapping execution
- Set up monitoring and alerts for failed jobs
- Consider timezone implications for global systems
- Test cron expressions thoroughly in staging environments
For complex scheduling needs, consider using more advanced job schedulers like Airflow, Celery, or Quartz that offer features like dependency management, retries, and distributed execution.
Remember that while cron is reliable for simple scheduling, it's not designed for complex workflows or high-availability systems. For production-critical jobs, implement redundancy and failover mechanisms.