Understanding cron
Five fields, one schedule.
Cryptic until you see the grid. Obvious afterwards.
The five fields.
A cron expression is five space-separated fields, read left to right: minute, hour, day of month, month, day of week. Each field accepts a number, a list, a range, a step, or a wildcard. Together they describe a schedule.
minute · hour · day · month · weekday
Field ranges
- minute — 0–59
- hour — 0–23
- day of month — 1–31
- month — 1–12 (or JAN–DEC)
- day of week — 0–6 (Sun = 0; or SUN–SAT)
The metacharacters.
Five small symbols carry the language. * means "every value in this field." , separates a list (1,15,30). - denotes a range (9-17). / is a step (*/15 means "every 15"). And ? appears in some implementations to mean "no specific value" in the day fields. That's the whole alphabet.
Four patterns worth memorising.
Read aloud as the schedule
0 * * * *every hour, on the hour*/5 * * * *every five minutes0 9 * * 1-509:00 every weekday0 0 1 * *midnight on the first of every month
The day-of-month and day-of-week trap.
When both day fields are anything other than *, they combine with OR, not AND. So 0 0 1 * 1 doesn't mean "midnight on the first of the month, but only if it's a Monday" — it means "midnight on the first of the month, OR midnight on every Monday." The second-most-common cron bug, behind UTC versus local time.
The shorthand.
Most cron implementations accept a few named shortcuts that replace all five fields: @hourly, @daily (midnight), @weekly (Sunday midnight), @monthly (1st of the month at midnight), @yearly (Jan 1 at midnight). They're identical to writing out the equivalent five-field expression and they read more clearly.
A note on time zones.
Classic Unix cron runs in the server's local time zone. Modern schedulers (GitHub Actions, AWS EventBridge, Kubernetes CronJobs) generally run in UTC unless told otherwise. The single most common cron bug is "this should have run at 9 AM and it ran at 5 AM" — daylight saving and zone offsets bite. When in doubt, write the expression in UTC and translate.
Read next