Reference, checked against crontab(5) and each platform’s docs
Cron expression examples
A cron expression is five fields separated by spaces: minute, hour, day of month, month and day of week. */5 * * * * runs every 5 minutes, 0 0 * * * every day at midnight, and 0 9 * * 1-5 at 09:00 on weekdays.
Each page below explains one schedule field by field, shows its next run times in your time zone and in UTC, and gives the same schedule for crontab, GitHub Actions, Kubernetes, Vercel, Cloudflare Workers, node-cron, systemd and Spring/Quartz, with the pitfalls specific to that schedule.
Every schedule
Seconds and minutes
| Schedule | Expression | Runs |
|---|---|---|
| Cron every 30 seconds | */30 * * * * * | Twice a minute (not possible in 5-field cron) |
| Cron every minute | * * * * * | At the start of every minute |
| Cron every 5 minutes | */5 * * * * | At minutes 0, 5, 10, …, 55 of every hour |
| Cron every 10 minutes | */10 * * * * | At minutes 0, 10, 20, 30, 40 and 50 |
| Cron every 15 minutes | */15 * * * * | At :00, :15, :30 and :45 of every hour |
| Cron every 30 minutes | */30 * * * * | At minutes 0 and 30 of every hour |
Hours
| Schedule | Expression | Runs |
|---|---|---|
| Cron every hour | 0 * * * * | At minute 0 of every hour |
| Cron every 2 hours | 0 */2 * * * | At minute 0 of every even hour |
| Cron every 6 hours | 0 */6 * * * | At 00:00, 06:00, 12:00 and 18:00 |
| Cron every 12 hours | 0 */12 * * * | At 00:00 and 12:00 |
| Cron twice a day | 0 9,21 * * * | At 09:00 and 21:00 |
Days
| Schedule | Expression | Runs |
|---|---|---|
| Cron every day at midnight | 0 0 * * * | Once a day at 00:00 |
| Cron every day at noon | 0 12 * * * | Once a day at 12:00 |
| Cron every day at 9 AM | 0 9 * * * | Once a day at 09:00 |
| Cron every 3 days | 0 0 */3 * * | Days 1, 4, 7, …, 31 of each month at 00:00 |
Weekdays and weeks
| Schedule | Expression | Runs |
|---|---|---|
| Cron every weekday | 0 0 * * 1-5 | At 00:00, Monday to Friday |
| Cron every weekday at 9 AM | 0 9 * * 1-5 | At 09:00, Monday to Friday |
| Cron every weekend | 0 0 * * 0,6 | At 00:00 on Saturday and Sunday |
| Cron every Monday | 0 0 * * 1 | At 00:00 every Monday |
| Cron every Sunday | 0 0 * * 0 | At 00:00 every Sunday |
| Cron every week | 0 0 * * 0 | Once a week, Sunday at 00:00 |
Months, quarters and years
| Schedule | Expression | Runs |
|---|---|---|
| Cron every month | 0 0 1 * * | Once a month, the 1st at 00:00 |
| Cron on the first day of the month | 0 0 1 * * | Day 1 of every month at 00:00 |
| Cron on the last day of the month | 0 0 L * * | Last day of each month (needs L or a date check) |
| Cron every quarter | 0 0 1 1,4,7,10 * | Jan 1, Apr 1, Jul 1 and Oct 1 at 00:00 |
| Cron every year | 0 0 1 1 * | Once a year, January 1 at 00:00 |
Special
| Schedule | Expression | Runs |
|---|---|---|
| Cron @reboot: run a job at startup | @reboot | Once when the cron daemon starts after boot |
Cron syntax cheat sheet
The five fields
| # | Field | Allowed values | Names |
|---|---|---|---|
| 1 | Minute | 0-59 | |
| 2 | Hour | 0-23 | |
| 3 | Day of month | 1-31 | |
| 4 | Month | 1-12 | JAN-DEC |
| 5 | Day of week | 0-6, Sunday = 0 (7 is also Sunday in cronie, Debian, node-cron, Spring) | SUN-SAT |
Special characters
| Character | Meaning | Example |
|---|---|---|
* | Every value of the field | * * * * * every minute |
, | List of values | 0 9,17 * * * at 09:00 and 17:00 |
- | Inclusive range | 0 9 * * 1-5 Monday to Friday |
/ | Step, within the field | */15 * * * * minutes 0, 15, 30, 45 |
a-b/n | Step inside a range | 0 1-23/2 * * * odd hours |
L (last), W (nearest weekday), # (nth weekday) and ? (no value) are Quartz extensions. Spring, node-cron and Cloudflare accept most of them; crontab, GitHub Actions, Kubernetes and Vercel don’t.
Macros
| Macro | Same as | Runs |
|---|---|---|
@yearly, @annually | 0 0 1 1 * | January 1 at 00:00 |
@monthly | 0 0 1 * * | The 1st of each month at 00:00 |
@weekly | 0 0 * * 0 | Sunday at 00:00 |
@daily, @midnight | 0 0 * * * | Every day at 00:00 |
@hourly | 0 * * * * | Minute 0 of every hour |
@reboot | (no time) | Once when the cron daemon starts |
How cron decides when to run
It checks every minute
The daemon wakes up once a minute and starts every job whose minute, hour and month fields match the current time and whose day fields match today. There’s no memory of past runs: a missed minute is simply missed, which is why anacron and systemd’s Persistent=true exist.
Steps restart in every field
A step like */7 only repeats inside its own field. Minutes go 0, 7, …, 56 and then back to 0, so the gap across the hour is 4 minutes. The same happens with hours (*/5) and days (*/3 restarts on the 1st). Only steps that divide the field evenly give a steady interval.
Day of month OR day of week
crontab(5): if both day fields are restricted, the job runs when either matches. 30 4 1,15 * 5 runs on the 1st, the 15th and every Friday. A field that starts with * counts as unrestricted in cronie, even */2. node-cron and systemd use AND instead, Vercel refuses both, and Quartz makes you put ? in one.
Time zones and DST
A crontab follows the server’s zone; cronie also reads CRON_TZ. Hosted schedulers mostly use UTC. In zones with daylight saving time, jobs between 01:00 and 03:00 local are the ones that get skipped or repeated, so avoid that window or schedule in UTC.
Platform differences
The same five fields behave slightly differently depending on where they run. Checked against each vendor’s documentation on the review date below.
| Platform | Time zone | Shortest interval | Seconds | Weekdays and extensions |
|---|---|---|---|---|
| crontab (cronie, Debian) | Server, or CRON_TZ (cronie) | 1 minute | No | 0-7, names; macros; no L |
| GitHub Actions | UTC, or timezone | 5 minutes, may be delayed | No | 0-6, names; no macros |
| Kubernetes CronJob | spec.timeZone, else controller’s zone | 1 minute | No | 0-6, names; macros; ? = * |
| Vercel | UTC only | 1 minute (Pro), 1 day (Hobby) | No | 0-6; no names; not both day fields |
| Cloudflare Workers | UTC only | 1 minute | No | 1 = Sunday … 7 = Saturday; L, W, # |
| node-cron 4.x | Process, or timezone option | 1 second | Optional 1st field | 0-7, names; L, W, #; day fields ANDed |
| systemd timer | System, or zone suffix | Sub-second (set AccuracySec) | Yes | Own syntax: Mon..Fri *-*-* 09:00 |
Spring @Scheduled | JVM, or zone | 1 second | Required 1st field | 0-7, names; L, W, #; macros |
| Quartz | JVM, or trigger zone | 1 second | Required 1st field | 1 = Sunday … 7 = Saturday; ? required |
Tools
To build an expression by picking options, or to paste one and read it in plain language:
Frequently asked questions
- What are the five fields of a cron expression?
- Minute (0-59), hour (0-23), day of month (1-31), month (1-12) and day of week (0-6, Sunday = 0, and 7 is also Sunday in most crons). A crontab line adds the command after them.
- What time zone does cron use?
- A crontab uses the server’s local time zone (cronie also reads CRON_TZ). GitHub Actions uses UTC unless you set timezone, Kubernetes uses spec.timeZone or the controller’s zone, and Vercel and Cloudflare always use UTC.
- What happens when both day of month and day of week are set?
- In standard cron the job runs when either one matches: 0 0 1 * 1 runs on the 1st and on every Monday. node-cron and systemd use AND instead, Vercel forbids setting both, and Quartz requires ? in one of them.
- Can cron run jobs every few seconds?
- No. Five-field cron has one-minute resolution. Use two lines with sleep, a systemd timer, or a 6-field scheduler such as node-cron or Spring for sub-minute schedules.
- How do I check a cron expression before deploying it?
- Look at its next run times. Each page here lists them, the cron-to-human tool on this site explains any expression, and on Linux systemd-analyze calendar does the same for OnCalendar values.
Last reviewed by Arielton Oberek.