The Five Fields
A crontab schedule has five fields separated by spaces:
* * * * * command
| | | | |
| | | | +-- Day of week (0-7, where 0 and 7 are Sunday)
| | | +---- Month (1-12)
| | +------ Day of month (1-31)
| +-------- Hour (0-23)
+---------- Minute (0-59)
Basic Patterns
Every Minute
* * * * * /path/to/script.sh
Runs every single minute. Useful for real-time monitoring but resource-intensive.
Every Hour
0 * * * * /path/to/script.sh
Runs at minute 0 of every hour.
Every Day at Midnight
0 0 * * * /path/to/script.sh
Every Monday at 9 AM
0 9 * * 1 /path/to/script.sh
First Day of Every Month at 6 AM
0 6 1 * * /path/to/script.sh
Special Characters
Comma: Multiple Values
# Run at 9 AM, 12 PM, and 5 PM
0 9,12,17 * * * /path/to/script.sh
Dash: Range
# Run every hour from 9 AM to 5 PM
0 9-17 * * * /path/to/script.sh
Slash: Step Values
# Run every 5 minutes
*/5 * * * * /path/to/script.sh
# Run every 2 hours
0 */2 * * * /path/to/script.sh
Real-World Examples
Database Backup - Daily at 2 AM
0 2 * * * /usr/local/bin/backup-db.sh
Log Rotation - Weekly on Sunday at 4 AM
0 4 * * 0 /usr/sbin/logrotate /etc/logrotate.conf
Health Check - Every 5 Minutes During Business Hours
*/5 9-17 * * 1-5 /path/to/health-check.sh
Monthly Report - First Monday of Every Month
This one is tricky. Cron does not natively support "first Monday." Use a wrapper:
# Run on the 1st through 7th, but only if it is Monday
0 9 1-7 * 1 /path/to/monthly-report.sh
Quarterly Cleanup - Jan, Apr, Jul, Oct
0 3 1 1,4,7,10 * /path/to/quarterly-cleanup.sh
Special Strings
Some cron implementations support shorthand strings:
@reboot Run once at startup
@yearly 0 0 1 1 *
@monthly 0 0 1 * *
@weekly 0 0 * * 0
@daily 0 0 * * *
@hourly 0 * * * *
Common Mistakes
Forgetting Timezone
Cron uses the system timezone. If your server is UTC but you want jobs to run at 9 AM local time, you need to calculate the UTC equivalent. Or set the timezone in crontab:
CRON_TZ=America/New_York
0 9 * * * /path/to/script.sh
Day-of-Month AND Day-of-Week
When both day-of-month and day-of-week are set (not *), cron runs the job when either matches, not when both match. This surprises many people.
# Runs on the 15th AND every Friday, not "Friday the 15th"
0 9 15 * 5 /path/to/script.sh
Minute Field Wildcard
# BAD: runs every minute of every hour
* */2 * * * /path/to/script.sh
# GOOD: runs once every 2 hours at minute 0
0 */2 * * * /path/to/script.sh
Testing Your Crontab
Before deploying, verify your schedule does what you think it does. Online tools like crontab.guru let you paste a cron expression and see the next execution times.
And regardless of how correct your syntax is, monitor your cron jobs to confirm they actually run. A perfectly written crontab on a server that lost its cron daemon does nothing at all.
Frequently asked questions about crontab syntax
What do the five crontab fields mean? A crontab schedule has five fields separated by spaces, and they run left to right: minute (0-59), hour (0-23), day of month (1-31), month (1-12), and day of week (0-7, where both 0 and 7 mean Sunday). Everything after those five fields is the command to run, so a line of five asterisks followed by a command runs that command every single minute.
How do I run a job every few minutes or every few hours? Use the slash character for step values: a schedule of star-slash-5 in the minute field runs every 5 minutes, and 0 with star-slash-2 in the hour field runs every 2 hours. The common mistake here is leaving the minute field as a plain asterisk while stepping the hour field, because that runs the job every minute of every other hour rather than once every 2 hours. Put 0 in the minute field when you want a single run per interval.
Why does my job run on both the 15th and every Friday? Because when both day-of-month and day-of-week are set to something other than an asterisk, cron runs the job when either field matches, not when both match. A schedule of 0 9 15 * 5 therefore runs on the 15th and on every Friday, not on "Friday the 15th." This surprises many people.
How do I make cron run a job in a specific timezone? Cron uses the system timezone by default, so if your server is UTC but you want a job to run at 9 AM local time, you either calculate the UTC equivalent yourself or set the timezone in the crontab with a CRON_TZ line above the schedule.
Can cron schedule something like the first Monday of every month? Not natively, so you need a wrapper around it. The usual trick is to schedule the job for the 1st through the 7th of the month and also restrict it to Monday, which means it fires only on the one day in that window that is a Monday. Before deploying any schedule, verify it does what you think: online tools like crontab.guru let you paste a cron expression and see the next execution times.
Further reading
- 10 Cron Job Best Practices Every Engineer Should Follow
- Why Cron Jobs Fail Silently (And How to Catch Them)
- Dead Man's Switch Monitoring: The Only Reliable Way to Watch Cron Jobs
Conclusion: Crontab syntax is simple but has sharp edges. The day-of-month/day-of-week OR behavior, timezone assumptions, and minute-field wildcards trip up even experienced engineers. Use shorthand strings when possible, test expressions before deploying, and always monitor that jobs actually execute.
Sources: crontab(5) manual.