The Ultimate Guide to Cron Jobs: A Beginner-to-Advanced Tutorial
If you've ever needed to run a script automatically—backups at 2 AM, reports every Monday, cache clearing every hour—you need cron. This is the complete guide that takes you from "What is cron?" to building complex automated workflows like a senior DevOps engineer.
No fluff. No outdated syntax. Just everything you need to master cron scheduling in 2025.
What is a Cron Job?
A cron job is a time-based task scheduler in Unix-like operating systems (Linux, macOS, BSD). It runs commands or scripts automatically at specified times, dates, or intervals without any human intervention.
Think of it as your server's personal assistant that never sleeps, never forgets, and executes tasks with perfect timing.
Real-World Use Cases
- Automated Backups: Database dumps every night at 2 AM
- Log Rotation: Clean up old logs weekly to save disk space
- Report Generation: Send analytics emails every Monday morning
- System Maintenance: Clear caches, update indexes, check for updates
- Monitoring: Health checks every 5 minutes
- Data Sync: Pull data from APIs hourly
- Certificate Renewal: Check SSL certificates monthly
- Cleanup Tasks: Delete temporary files daily
If it needs to happen on a schedule, cron can do it.
How Cron Works
The Cron Daemon
The cron daemon (or crond) is a background service that runs continuously on your system. Every minute, it wakes up, checks all scheduled tasks, and executes any that are due.
Check if cron is running:
# On most Linux systems
systemctl status cron
# Or
systemctl status crond
# On macOS
sudo launchctl list | grep cron
The Crontab File
Your scheduled tasks live in a crontab (cron table) file. Each user on the system can have their own crontab with different scheduled tasks.
Important: Never edit the crontab file directly with a text editor. Always use the crontab command to avoid syntax errors that could break all your scheduled tasks.
Cron Syntax: The Five Fields
Every cron expression consists of five fields followed by the command to execute:
* * * * * command-to-execute
│ │ │ │ │
│ │ │ │ └─── Day of Week (0-6, Sunday=0 or 7)
│ │ │ └───── Month (1-12)
│ │ └─────── Day of Month (1-31)
│ └───────── Hour (0-23)
└─────────── Minute (0-59)
Field Values
| Field | 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-6 or SUN-SAT | * , - / ? L # |
Special Characters Explained
Asterisk (*) - "Every" or "Any"
* * * * *= Every minute0 * * * *= Every hour at minute 0
Comma (,) - List multiple values
0 9,17 * * *= At 9 AM and 5 PM0 0 * * 1,5= Midnight on Monday and Friday
Hyphen (-) - Range of values
0 9-17 * * *= Every hour from 9 AM to 5 PM0 0 * * 1-5= Midnight Monday through Friday
Slash (/) - Step values (intervals)
*/15 * * * *= Every 15 minutes0 */6 * * *= Every 6 hours*/5 9-17 * * *= Every 5 minutes during business hours
Beginner Examples
Let's start with common patterns you'll use constantly.
Every Minute
* * * * * /path/to/script.sh
Use case: Testing, monitoring checks
Every Hour
0 * * * * /usr/bin/php /var/www/cleanup.php
Use case: Cache clearing, hourly sync
Every Day at Midnight
0 0 * * * /usr/local/bin/backup.sh
Use case: Daily backups, log rotation
Every Weekday at 9 AM
0 9 * * 1-5 /usr/bin/send-report.sh
Use case: Business reports, weekday notifications
Every Sunday at 2 AM
0 2 * * 0 /usr/local/bin/weekly-maintenance.sh
Use case: Weekly tasks, full system backups
First Day of Every Month
0 0 1 * * /usr/bin/monthly-billing.sh
Use case: Billing runs, monthly reports
Every 15 Minutes
*/15 * * * * /usr/bin/monitor-health.sh
Use case: Health checks, API polling
Every 6 Hours
0 */6 * * * /usr/bin/sync-data.sh
Use case: Data synchronization
Managing Your Crontab
View Current Crontab
crontab -l
Edit Crontab
crontab -e
This opens your crontab in the default editor (usually vi or nano).
Remove All Cron Jobs
crontab -r
Warning: This deletes EVERYTHING. No confirmation prompt.
Edit Another User's Crontab (as root)
sudo crontab -u username -e
Backup Your Crontab
crontab -l > ~/crontab-backup.txt
Always backup before making changes!
Restore from Backup
crontab ~/crontab-backup.txt
Intermediate Techniques
Using Environment Variables
Cron runs with a minimal environment. Set variables at the top of your crontab:
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=admin@example.com
0 2 * * * /usr/local/bin/backup.sh
Common Variables:
SHELL: Which shell to use (default:/bin/sh)PATH: Search path for executablesMAILTO: Email address for output (blank to disable)HOME: Home directory for scripts
Redirecting Output
By default, cron emails you the output. Control where it goes:
# Redirect to log file
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
# Redirect to null (silence everything)
0 2 * * * /usr/local/bin/backup.sh > /dev/null 2>&1
# Only log errors
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Understanding redirections:
>>= Append to file (don't overwrite)2>&1= Redirect stderr to stdout> /dev/null= Discard output
Multiple Commands
Run multiple commands in sequence:
# Using semicolons
0 2 * * * cd /var/backups && tar -czf backup.tar.gz /data && rm -f old-backup.tar.gz
# Using && (stop if one fails)
0 2 * * * command1 && command2 && command3
# Using a script (recommended)
0 2 * * * /usr/local/bin/run-all-backups.sh
Running Scripts with Specific Users
# Run as specific user
sudo crontab -u www-data -e
# Or use sudo in the command
0 2 * * * sudo -u www-data /var/www/cleanup.sh
Advanced Patterns
Business Hours Only
# Every 30 minutes from 9 AM to 5 PM, weekdays
*/30 9-17 * * 1-5 /usr/bin/business-task.sh
Multiple Specific Times
# At 6 AM, noon, 6 PM, and midnight
0 0,6,12,18 * * * /usr/bin/check-status.sh
Quarterly Tasks
# First day of each quarter at 1 AM
0 1 1 1,4,7,10 * /usr/bin/quarterly-report.sh
Every Other Hour During Workday
0 9-17/2 * * 1-5 /usr/bin/periodic-check.sh
This runs at 9 AM, 11 AM, 1 PM, 3 PM, 5 PM on weekdays.
Complex Combined Ranges
# Every 10 minutes during peak hours (9-11 AM and 2-5 PM)
*/10 9-11,14-17 * * 1-5 /usr/bin/peak-monitor.sh
Using Month Names
# Every Monday in January, April, July, October
0 9 * JAN,APR,JUL,OCT 1 /usr/bin/seasonal-task.sh
Using Day Names
# 8 PM every Friday
0 20 * * FRI /usr/bin/friday-tasks.sh
Special Cron Shortcuts
Some systems support these convenient shortcuts:
@reboot # Run once at startup
@yearly # 0 0 1 1 * (January 1st midnight)
@annually # Same as @yearly
@monthly # 0 0 1 * * (First of month)
@weekly # 0 0 * * 0 (Sunday midnight)
@daily # 0 0 * * * (Every midnight)
@midnight # Same as @daily
@hourly # 0 * * * * (Every hour)
Examples:
@reboot /usr/local/bin/startup-script.sh
@daily /usr/local/bin/backup.sh
@weekly /usr/local/bin/weekly-cleanup.sh
Note: Not all systems support these. Test first!
Real Production Examples
1. Database Backup with Rotation
# Backup MySQL database daily at 2:30 AM
30 2 * * * /usr/local/bin/mysql-backup.sh
# Delete backups older than 7 days at 3 AM
0 3 * * * find /var/backups/mysql -name "*.sql.gz" -mtime +7 -delete
Script: /usr/local/bin/mysql-backup.sh
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/var/backups/mysql"
mysqldump -u root -p$MYSQL_PASSWORD mydatabase | gzip > $BACKUP_DIR/backup_$DATE.sql.gz
2. Log Rotation
# Compress logs weekly on Sunday at 1 AM
0 1 * * 0 gzip -f /var/log/app/*.log
# Delete compressed logs older than 30 days
0 2 * * 0 find /var/log/app -name "*.log.gz" -mtime +30 -delete
3. SSL Certificate Renewal (Let's Encrypt)
# Check and renew certificates at 3:30 AM on the 1st and 15th
30 3 1,15 * * certbot renew --quiet && systemctl reload nginx
4. System Health Monitoring
# Check disk space every hour
0 * * * * df -h | mail -s "Disk Space Report" admin@example.com
# Check if critical services are running every 5 minutes
*/5 * * * * systemctl is-active nginx || systemctl restart nginx
5. API Data Sync
# Fetch data from API every 15 minutes during business hours
*/15 9-17 * * 1-5 /usr/local/bin/sync-api-data.sh >> /var/log/api-sync.log 2>&1
6. Cache Warming
# Warm cache before traffic spike (7:30 AM weekdays)
30 7 * * 1-5 /usr/local/bin/warm-cache.sh
7. Cleanup Temporary Files
# Delete files in /tmp older than 2 days, every 6 hours
0 */6 * * * find /tmp -type f -mtime +2 -delete
Cron Best Practices
1. Always Use Absolute Paths
Wrong:
0 2 * * * backup.sh
Right:
0 2 * * * /usr/local/bin/backup.sh
Cron doesn't use your normal PATH. Be explicit.
2. Test Scripts Manually First
Before adding to cron:
# Run as the same user cron will use
/usr/local/bin/backup.sh
# Check exit code
echo $?
3. Add Logging
Always redirect output:
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Add timestamps in your scripts:
#!/bin/bash
echo "[$(date)] Starting backup..."
# Your commands here
echo "[$(date)] Backup complete"
4. Use Locking for Long-Running Tasks
Prevent overlapping executions:
#!/bin/bash
LOCKFILE=/var/lock/backup.lock
if [ -f "$LOCKFILE" ]; then
echo "Backup already running"
exit 1
fi
touch "$LOCKFILE"
trap "rm -f $LOCKFILE" EXIT
# Your backup commands here
/usr/bin/mysqldump...
5. Set Email Notifications
Add to top of crontab:
MAILTO=admin@example.com
# Or disable emails
MAILTO=""
6. Comment Your Crontab
# Database backup - runs at 2 AM daily
0 2 * * * /usr/local/bin/backup.sh
# Log cleanup - runs weekly on Sunday
0 3 * * 0 /usr/local/bin/cleanup-logs.sh
7. Validate Before Saving
Use our cron expression generator to validate syntax before adding to crontab.
8. Use Source for Environment
If your script needs specific environment variables:
0 2 * * * /bin/bash -l -c 'source ~/.bashrc && /usr/local/bin/backup.sh'
9. Handle Errors Gracefully
#!/bin/bash
if ! /usr/bin/mysqldump database > backup.sql; then
echo "Backup failed!" | mail -s "URGENT: Backup Failed" admin@example.com
exit 1
fi
10. Monitor Cron Job Execution
Set up monitoring to alert if jobs don't run:
- Use external monitoring (e.g., Cronitor, Healthchecks.io)
- Write completion markers to files
- Track execution in logs
System-Wide Cron Directories
Besides user crontabs, Linux systems have these directories:
/etc/cron.d/
Put files here with the same syntax as crontab, but with username:
# /etc/cron.d/myapp
0 2 * * * root /usr/local/bin/backup.sh
/etc/cron.hourly/
Scripts here run every hour. Just drop executable files.
/etc/cron.daily/
Scripts run once per day.
/etc/cron.weekly/
Scripts run once per week.
/etc/cron.monthly/
Scripts run once per month.
Note: These directories don't use cron syntax. Just make the file executable:
chmod +x /etc/cron.daily/backup.sh
Troubleshooting Cron Jobs
Check if Cron is Running
systemctl status cron
ps aux | grep cron
View Cron Logs
# On Ubuntu/Debian
grep CRON /var/log/syslog
# On CentOS/RHEL
tail -f /var/log/cron
# On macOS
log show --predicate 'process == "cron"' --last 1h
Test Your Cron Expression
Use our decoder tool to see when your cron will run next.
Common Issues
Job not running at all:
- Check cron syntax with our validator
- Verify cron daemon is running
- Check user permissions
- Look for syntax errors in crontab
Script works manually but not in cron:
- Use absolute paths everywhere
- Set environment variables
- Check script permissions (
chmod +x) - Add logging to see what's happening
No output/emails:
- Check MAILTO setting
- Verify mail system is configured
- Check spam folder
- Add explicit logging
Advanced: Anacron for Laptops
Cron only runs jobs at specific times. If your computer is off, the job is missed. Anacron runs missed jobs when the system boots.
Install:
sudo apt install anacron
Edit /etc/anacrontab:
# period delay job-id command
1 5 daily-backup /usr/local/bin/backup.sh
7 10 weekly-update /usr/local/bin/update.sh
period: Days between runsdelay: Minutes to wait after bootjob-id: Unique identifiercommand: What to run
Cron in Docker Containers
Running cron in Docker requires special setup:
Dockerfile:
FROM ubuntu:22.04
# Install cron
RUN apt-get update && apt-get install -y cron
# Copy crontab file
COPY crontab /etc/cron.d/myapp-cron
RUN chmod 0644 /etc/cron.d/myapp-cron
RUN crontab /etc/cron.d/myapp-cron
# Run cron in foreground
CMD ["cron", "-f"]
crontab file:
*/5 * * * * /usr/local/bin/task.sh >> /var/log/cron.log 2>&1
Cron Alternatives
While cron is the standard, consider these alternatives for specific use cases:
Systemd Timers
Modern alternative to cron on systemd-based Linux:
# More precise timing
# Better logging integration
# Service dependencies
Kubernetes CronJobs
For containerized environments:
apiVersion: batch/v1
kind: CronJob
metadata:
name: backup
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: backup:latest
Cloud Schedulers
- AWS EventBridge
- Google Cloud Scheduler
- Azure Logic Apps
Use when you need:
- Serverless execution
- Cloud-native integration
- No server maintenance
Quick Reference Card
# Field order
# * * * * * command
# │ │ │ │ │
# │ │ │ │ └─ Day of Week (0-6)
# │ │ │ └─── Month (1-12)
# │ │ └───── Day of Month (1-31)
# │ └─────── Hour (0-23)
# └───────── Minute (0-59)
# Common patterns
*/5 * * * * # Every 5 minutes
0 * * * * # Every hour
0 0 * * * # Daily at midnight
0 0 * * 0 # Weekly on Sunday
0 0 1 * * # Monthly on 1st
0 9-17 * * 1-5 # Weekdays, business hours
# Special strings
@reboot # At startup
@daily # Once per day
@weekly # Once per week
@monthly # Once per month
@yearly # Once per year
# Management commands
crontab -l # List jobs
crontab -e # Edit jobs
crontab -r # Remove all jobs
crontab -u user # For specific user
Next Steps
You now know everything you need to master cron jobs. But syntax is only half the battle.
Want to create perfect cron expressions without memorizing syntax?
Use our visual cron generator to:
- Build expressions with dropdowns (no syntax errors)
- See human-readable explanations instantly
- Test patterns before deploying
- Save and share configurations
Or paste existing cron expressions into our decoder to understand exactly what they do.
Stop fighting with syntax. Start automating like a pro.
Related Articles
Continue Learning:
- Cron Operators Explained: *, /, -, and , - Deep dive into cron syntax symbols
- Why Your Cron Job Isn't Running - Troubleshooting common cron issues
- Environment Variables in Cron Jobs - Fix PATH and env var problems
- Stop Googling Cron Jobs - Build a personal cron reference system
- Where Did My Cron Job Output Go? - Master logging and debugging
Advanced Topics:
- Automate Database Backups with Cron - Production-ready backup strategies
- Timezones in Cron Jobs: The Silent Killer - Handle timezone issues correctly
- Secure Your Cron Jobs from Attacks - Security best practices
This guide covers standard cron (Vixie cron). Some systems use variants with slight differences. Always test on your target system.