Back to blog
Best practices

Crontab Syntax Explained: From Basics to Advanced Schedules

A practical guide to crontab syntax covering minute, hour, day, month, and weekday fields with real examples for common scheduling patterns.

CronGuard Team··6 min read

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.

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.

Back to all posts