Mastering Cron Jobs: The Complete Guide to Scheduling Tasks
If you've ever needed to automate a task on Linux or Unixβwhether it's running backups, sending scheduled emails, or cleaning up old filesβyou've likely encountered cron. Despite being over 50 years old, cron remains the standard for job scheduling on Unix-like systems, running billions of automated tasks every day.
Yet cron syntax is notoriously cryptic. What does */5 * * * * mean? How about 0 9 * * 1-5? And why does * * * * * run 1,440 times per day instead of once?
This comprehensive guide covers everything you need to know about cron: from basic syntax to advanced patterns, common pitfalls to best practices. By the end, you'll be writing cron expressions confidently and avoiding the mistakes that cause scheduled jobs to fail.
What is Cron?
Cron is a time-based job scheduler in Unix-like operating systems (Linux, macOS, FreeBSD, etc.). The name comes from "chronos," the Greek word for time. Cron enables users to schedule jobs (commands or scripts) to run automatically at specified times, dates, or intervals.
Key concepts:
- Cron daemon (crond): The background service that checks crontabs every minute and executes scheduled jobs
- Crontab: The configuration file that defines scheduled jobs (short for "cron table")
- Cron expression: The syntax that specifies when a job should run
Common Use Cases for Cron
- Backups: Daily database backups at 2 AM when traffic is low
- Maintenance: Weekly log rotation, temporary file cleanup, cache clearing
- Monitoring: Periodic health checks, disk space monitoring, uptime pings
- Data processing: Hourly ETL jobs, report generation, data aggregation
- Notifications: Scheduled emails, reminder messages, alert digests
- Content management: Publishing scheduled posts, expiring old content
Understanding Cron Syntax
A cron expression consists of five time and date fields, followed by the command to execute. Here's the basic structure:
Field meanings:
| Field | Range | Special Values | Description |
|---|---|---|---|
| Minute | 0-59 | * , - / | Which minute of the hour |
| Hour | 0-23 | * , - / | Which hour of the day (0 = midnight) |
| Day of Month | 1-31 | * , - / | Which day of the month |
| Month | 1-12 | * , - / or JAN-DEC | Which month (1 = January) |
| Day of Week | 0-7 | * , - / or SUN-SAT | Which day of the week (0 and 7 = Sunday) |
Special Characters in Cron Expressions
- Asterisk (*): Matches all values (every minute, every hour, etc.)
- Comma (,): List separator (1,3,5 = "1 and 3 and 5")
- Hyphen (-): Range (1-5 = "1 through 5")
- Slash (/): Step values (*/5 = "every 5 units")
Common Cron Patterns with Examples
Every Minute, Hour, Day
Every Minute
* * * * *
Runs every single minute (1,440 times per day). Use with caution!
Example: High-frequency monitoring or heartbeat checks
Every 5 Minutes
*/5 * * * *
Runs at :00, :05, :10, :15, :20, :25, :30, :35, :40, :45, :50, :55 of each hour (288 times per day)
Example: API polling, status checks
Every Hour
0 * * * *
Runs at the top of every hour (:00)
Example: Hourly data sync, cache refresh
Every Day at Midnight
0 0 * * *
Runs once per day at 12:00 AM
Example: Daily backups, log rotation, report generation
β οΈ Common Mistake: Using * for Everything
Many beginners think * * * * * means "run once per hour" or "run once per day." It actually means "run every minute"βthat's 1,440 executions per day!
Correct patterns:
- Every hour:
0 * * * *(not* * * * *) - Every day:
0 0 * * *(not* * * *)
Business Hours and Weekday Patterns
Weekdays at 9 AM
0 9 * * 1-5
Runs Monday through Friday at 9:00 AM
Example: Morning reports, business hour notifications
Weekdays Every Hour (9 AM - 5 PM)
0 9-17 * * 1-5
Runs every hour from 9 AM to 5 PM, Monday through Friday (45 times per week)
Example: Business hours monitoring
Weekends Only
0 0 * * 0,6
Runs at midnight on Saturday and Sunday
Example: Weekend maintenance tasks
π Day of Week Numbering
0 = Sunday, 1 = Monday, 2 = Tuesday, 3 = Wednesday, 4 = Thursday, 5 = Friday, 6 = Saturday
Note: Both 0 and 7 represent Sunday in most cron implementations.
Weekly, Monthly, Yearly Patterns
Weekly on Monday
0 0 * * 1
Runs every Monday at midnight
Example: Weekly reports, log archival
Monthly on the 1st
0 0 1 * *
Runs on the first day of every month at midnight
Example: Monthly billing, subscription renewals
Quarterly
0 0 1 1,4,7,10 *
Runs on January 1, April 1, July 1, and October 1 at midnight
Example: Quarterly reports, compliance tasks
Yearly on January 1
0 0 1 1 *
Runs once per year on January 1 at midnight
Example: Annual backups, year-end archival
Multiple Times Per Day
Twice Daily (6 AM and 6 PM)
0 6,18 * * *
Runs at 6:00 AM and 6:00 PM every day
Example: Bi-daily data sync
Every 2 Hours
0 */2 * * *
Runs at 0:00, 2:00, 4:00, 6:00, 8:00, 10:00, 12:00, 14:00, 16:00, 18:00, 20:00, 22:00
Example: Periodic cache warming
Every 12 Hours
0 0,12 * * *
Runs at midnight and noon
Example: Twice-daily backups
Advanced Cron Patterns
Step Values (The Slash Operator)
The slash (/) creates step values: */n means "every n units"
Every 10 Minutes
*/10 * * * *
Equivalent to: 0,10,20,30,40,50 * * * *
Every 15 Minutes
*/15 * * * *
Runs at :00, :15, :30, :45 of each hour
Every 4 Hours Starting at 1 AM
0 1-23/4 * * *
Runs at 1:00, 5:00, 9:00, 13:00, 17:00, 21:00
First and Last Occurrences
First Monday of Each Month
0 0 1-7 * 1
Runs on day 1-7 of the month, but only if it's a Monday
Explanation: The first Monday is guaranteed to fall between day 1 and day 7
β οΈ Last Day of Month (No Direct Syntax)
Cron has no native syntax for "last day of month" because month lengths vary (28-31 days).
Workaround: Use a wrapper script that checks if tomorrow is day 1:
0 0 * * * [ $(date -d tomorrow +\%d) -eq 1 ] && /path/to/script.sh
Combining Patterns
Weekdays at 9 AM and 5 PM
0 9,17 * * 1-5
Runs Monday-Friday at 9:00 AM and 5:00 PM (10 times per week)
Every 30 Minutes During Business Hours
*/30 9-17 * * 1-5
Runs every 30 minutes from 9:00 AM to 5:30 PM on weekdays
Common Cron Mistakes and How to Avoid Them
1. Forgetting About Timezones
Problem: Cron uses the system's timezone. If your server is in UTC but you expect EST, your 9 AM job runs at 2 PM!
Solution: Check timezone with date command or set explicitly:
TZ=America/New_York 0 9 * * * /script.sh
2. Daylight Saving Time Issues
Problem: During DST transitions, midnight may not exist (spring forward) or happen twice (fall back).
Solution: For critical jobs, schedule at 1 AM or 2 AM instead of midnight to avoid DST edge cases.
3. Not Handling Job Overlap
Problem: If a job takes 10 minutes but runs every 5 minutes, multiple instances overlap and conflict.
Solution: Use lock files or tools like flock:
*/5 * * * * flock -n /tmp/myjob.lock /path/to/script.sh
4. Ignoring Output and Errors
Problem: Cron emails output by default, but if email isn't configured, you never see errors.
Solution: Redirect output to log files:
0 2 * * * /backup.sh >> /var/log/backup.log 2>&1
5. Using Relative Paths
Problem: Cron doesn't run in your user environment. Relative paths fail.
Solution: Always use absolute paths for scripts and commands:
0 0 * * * /usr/local/bin/backup.sh # Good
0 0 * * * ./backup.sh # Bad
Best Practices for Production Cron Jobs
1. Always Test Your Cron Expression
Before deploying, verify your cron expression does what you think. Use a cron expression calculator to see the next 10 execution times. A single mistake can cause jobs to run 1,440 times per day instead of once!
Test Your Cron Expressions
Use Cron Master to validate expressions, see execution times, and catch errors before deployment. Includes timezone support and execution previews.
Try Cron Master β2. Log Everything
Always log cron job execution: start time, end time, exit status, errors. This is invaluable for debugging and auditing.
3. Set Environment Variables
Cron runs with a minimal environment. Set PATH and other variables at the top of your crontab:
4. Monitor Cron Job Execution
Use monitoring tools to track whether cron jobs actually ran. Don't assume silence means success.
- Set up alerts if a job doesn't run on schedule
- Monitor job duration (suddenly slow jobs indicate problems)
- Track exit codes (non-zero means failure)
5. Document Your Cron Jobs
Add comments to your crontab explaining what each job does and why:
Managing Crontabs
Basic Crontab Commands
System-wide Cron Jobs
Beyond user crontabs, Unix systems have system-wide cron directories:
/etc/cron.d/- System cron jobs (requires username field)/etc/cron.daily/- Scripts run once per day/etc/cron.hourly/- Scripts run once per hour/etc/cron.weekly/- Scripts run once per week/etc/cron.monthly/- Scripts run once per month
Alternatives to Cron
While cron is ubiquitous, it has limitations. Here are modern alternatives:
| Tool | Best For | Key Feature |
|---|---|---|
| systemd timers | Modern Linux systems | Better logging, dependencies, resource control |
| Kubernetes CronJobs | Containerized workloads | Cloud-native, scalable, declarative |
| AWS EventBridge | AWS infrastructure | Serverless, integrated with AWS services |
| Airflow | Complex data pipelines | DAGs, retries, dependencies, monitoring |
| Celery Beat | Python applications | Dynamic schedules, distributed tasks |
Conclusion
Cron is one of those Unix tools that seems simple on the surface but has surprising depth. Mastering cron syntax, understanding its quirks, and following best practices will save you from late-night debugging sessions and mysterious job failures.
Key takeaways:
- Always test cron expressions before deploying to production
- Use absolute paths for all commands and scripts
- Log everything: start times, end times, errors
- Be aware of timezone and DST issues
- Monitor job executionβdon't assume success
- Document your cron jobs for future maintainers
Whether you're scheduling daily backups, running ETL pipelines, or sending automated reports, cron is an essential tool in your DevOps toolkit. Master it once, use it forever.
Need to test your cron expressions? Use Cron Master to validate syntax, preview execution times, and catch errors before deployment. Includes timezone support and human-readable descriptions.