Cron Syntax at a Glance
A cron expression has five fields separated by spaces:
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12 or JAN-DEC)
│ │ │ │ ┌───────────── day of week (0-7 or SUN-SAT)
│ │ │ │ │
* * * * *
Special Characters
| Character | Meaning | Example | Result |
|---|---|---|---|
* | Every value | * * * * * | Every minute |
, | List | 1,15 * * * * | At minute 1 and 15 |
- | Range | 0 9-17 * * * | Every hour from 9 AM to 5 PM |
/ | Step | */10 * * * * | Every 10 minutes |
- + / | Range with step | 0 8-18/2 * * * | Every 2 hours from 8 AM to 6 PM |
Common Schedules
Every N Minutes
| Expression | Fires | Per hour |
|---|---|---|
* * * * * | Every minute | 60 |
*/5 * * * * | Every 5 minutes | 12 |
*/10 * * * * | Every 10 minutes | 6 |
*/15 * * * * | Every 15 minutes | 4 |
*/30 * * * * | Every 30 minutes | 2 |
Hourly and Daily
| Expression | Fires |
|---|---|
0 * * * * | Top of every hour |
0 */2 * * * | Every 2 hours |
0 */6 * * * | Every 6 hours (midnight, 6 AM, noon, 6 PM) |
0 0 * * * | Daily at midnight |
0 6 * * * | Daily at 6 AM |
30 4 * * * | Daily at 4:30 AM (common for maintenance tasks) |
Weekday Schedules
| Expression | Fires |
|---|---|
0 9 * * 1-5 | Weekdays at 9 AM |
0 0 * * 1-5 | Weekdays at midnight |
0 9 * * 1 | Every Monday at 9 AM |
0 0 * * 0 | Every Sunday at midnight |
0 17 * * 5 | Every Friday at 5 PM |
Monthly and Yearly
| Expression | Fires |
|---|---|
0 0 1 * * | First day of every month at midnight |
0 0 15 * * | 15th of every month at midnight |
0 0 1 1 * | January 1st at midnight (yearly) |
0 0 1 */3 * | Every quarter (Jan, Apr, Jul, Oct) |
Aliases
Some cron implementations support shorthand aliases:
| Alias | Equivalent | Meaning |
|---|---|---|
@yearly | 0 0 1 1 * | Once a year (January 1st) |
@monthly | 0 0 1 * * | Once a month (1st at midnight) |
@weekly | 0 0 * * 0 | Once a week (Sunday midnight) |
@daily | 0 0 * * * | Once a day (midnight) |
@hourly | 0 * * * * | Once an hour (top of the hour) |
@reboot | N/A | Once at system startup |
Field Value Ranges
| Field | Range | Names allowed |
|---|---|---|
| Minute | 0-59 | No |
| Hour | 0-23 | No |
| Day of month | 1-31 | No |
| Month | 1-12 | JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC |
| Day of week | 0-7 | SUN, MON, TUE, WED, THU, FRI, SAT (0 and 7 are both Sunday) |
Month and day of week names are case insensitive in most implementations. Names work in ranges (MON-FRI) but not in steps (MON/2 is not valid).
Common Gotchas
OR logic between day fields
When both day of month and day of week are nonwildcard, standard cron uses OR logic. 0 9 15 * 1 fires on the 15th of every month AND every Monday, not just Mondays that are the 15th.
Timezone matters
Cron uses the system’s local timezone by default. If your server is in UTC but you schedule 0 9 * * * expecting 9 AM Eastern, the job runs at 4 or 5 AM Eastern (depending on DST). Set TZ=America/New_York in your crontab or use CRON_TZ if your implementation supports it.
Step values don’t carry over
*/5 in the minute field resets every hour. If a job runs at 10:55, the next execution is 11:00, not 11:05. The step always counts from the start of the range.
No second level precision
Standard cron’s smallest unit is 1 minute. For subminute scheduling, use a long running process with a sleep loop, a systemd timer, or a job scheduler like Celery Beat or Temporal.