Most of the time you need one working line, such as the one that runs your backup at 3 AM on the first Sunday of the month, more than an understanding of cron from first principles. This page collects sixty schedules we have needed in practice, grouped by how often they fire, with notes on how each one behaves. Every expression is standard five-field Unix cron unless the table says otherwise, and you can paste any of them into the Explainer to see its next run times.
Every N minutes
Step values in the minute field (*/n) cover almost every sub-hourly schedule. A step divides the whole 0-59 range, so the runs are evenly spaced only when n divides 60.
| Expression | Runs | Notes |
|---|---|---|
* * * * * | Every minute | 1,440 runs a day, the fastest schedule standard cron supports. |
*/2 * * * * | Every 2 minutes | Fires on even minutes: :00, :02, :04… |
*/5 * * * * | Every 5 minutes | The most common polling interval. |
*/10 * * * * | Every 10 minutes | :00, :10, :20, :30, :40, :50. |
*/15 * * * * | Every 15 minutes | Four runs an hour, on the quarter. |
*/30 * * * * | Every 30 minutes | Equivalent to 0,30 * * * *. |
*/7 * * * * | Every 7 minutes, resetting each hour | :00, :07…:56, then :00 again. The gap at the hour boundary is 4 minutes because 7 does not divide 60. |
7 * * * * | At 7 minutes past every hour | Moving off :00 avoids the traffic spike created by all the other jobs that run on the hour. |
0,15,30,45 * * * * | Every 15 minutes | An explicit list; identical to */15 but clearer to some readers. |
*/5 * * * 1-5 | Every 5 minutes, Monday to Friday | No runs on Saturday or Sunday. |
A step always counts from the start of its field's range and does not track when the previous run happened. */7 means "every 7th minute of each hour" rather than "every 7 minutes forever", so the gap between 23:56 and 00:00 is four minutes instead of seven. For a true fixed interval that does not divide an hour, use a scheduler that supports intervals.
Hourly and every N hours
Put a fixed value in the minute field and a step or range in the hour field. Leaving the minute as * is nearly always a mistake: * */2 * * * runs sixty times in each of those hours, not once.
| Expression | Runs | Notes |
|---|---|---|
0 * * * * | Every hour, on the hour | 24 runs a day. |
30 * * * * | Every hour at half past | Useful for staggering against hourly jobs on :00. |
0 */2 * * * | Every 2 hours | 00:00, 02:00, 04:00…22:00. |
0 */3 * * * | Every 3 hours | Eight runs a day starting at midnight. |
0 */4 * * * | Every 4 hours | 00:00, 04:00, 08:00, 12:00, 16:00, 20:00. |
0 */6 * * * | Every 6 hours | Four runs a day. |
0 */12 * * * | Twice a day | Midnight and noon. |
0 9-17 * * * | Hourly from 09:00 to 17:00 | Nine runs, because the range includes both ends. |
0 8-18/2 * * * | Every 2 hours between 08:00 and 18:00 | 08:00, 10:00, 12:00, 14:00, 16:00, 18:00. A step applied to a range. |
15,45 * * * * | Twice an hour, at :15 and :45 | A list in the minute field. |
Daily at a fixed time
Cron uses 24-hour time and has no AM/PM and no seconds field. 0 18 * * * is 6 PM, and it fires at 18:00:00 in the server's time zone, whatever that is set to.
| Expression | Runs | Notes |
|---|---|---|
0 0 * * * | Every day at midnight | The classic nightly job. Equivalent to @daily. |
30 2 * * * | Every day at 02:30 | A common backup window, but see the DST warning below. |
0 3 * * * | Every day at 03:00 | Safely past the daylight saving transition hour in most zones. |
0 6 * * * | Every day at 06:00 | Morning report generation. |
0 12 * * * | Every day at noon | |
0 18 * * * | Every day at 18:00 | 6 PM in 24-hour time. |
0 23 * * * | Every day at 23:00 | End-of-day rollup before the date changes. |
0 0,12 * * * | Twice daily, midnight and noon | A list is clearer than */12 when the two times are not evenly spaced. |
In zones that observe daylight saving, a daily job scheduled between roughly 01:00 and 03:00 will be skipped on the spring-forward day, or run twice on the fall-back day, depending on your cron implementation. Scheduling at 0 3 * * * or later avoids the problem. The time zones and DST guide describes what each implementation does.
Weekdays, weekends and business hours
Day of week is the fifth field, numbered 0 (Sunday) through 6 (Saturday). Most implementations also accept 7 for Sunday and three-letter names such as MON.
| Expression | Runs | Notes |
|---|---|---|
0 9 * * 1-5 | Weekdays at 09:00 | Monday through Friday. |
0 9 * * MON-FRI | Weekdays at 09:00 | Identical, using names. Names are case-insensitive but less portable than numbers. |
0 18 * * 1-5 | Weekdays at 18:00 | End-of-workday jobs. |
0 0 * * 6,0 | Weekends at midnight | Saturday and Sunday. |
0 2 * * 6 | Saturdays at 02:00 | Weekly maintenance while nobody is working. |
*/15 9-17 * * 1-5 | Every 15 minutes, 09:00-17:59, weekdays | 36 runs per weekday. The 17 covers the whole 17:00 hour, so the last run is 17:45. |
0 9-17 * * 1-5 | Hourly during business hours, weekdays | Nine runs a day, 45 a week. |
*/30 8-18 * * 1-5 | Every half hour, 08:00-18:59, weekdays | Extend the hour range by one if you want coverage through the end of the day. |
Weekly
A weekly schedule is a daily schedule with the day-of-week field restricted and the day-of-month field left as *. Restricting both is the most common cron mistake, and the last section explains why.
| Expression | Runs | Notes |
|---|---|---|
0 0 * * 0 | Every Sunday at midnight | Equivalent to @weekly. |
0 0 * * 1 | Every Monday at midnight | Start-of-week reset. |
0 4 * * 0 | Every Sunday at 04:00 | Weekly full backup. |
0 8 * * 1 | Every Monday at 08:00 | Weekly summary email before the day starts. |
0 17 * * 5 | Every Friday at 17:00 | End-of-week report. |
0 12 * * 1,3,5 | Monday, Wednesday and Friday at noon | A list in the day-of-week field. |
Monthly
Day of month is the third field, 1 to 31. Standard cron has no "last day of month" token, which is why the workarounds below exist.
| Expression | Runs | Notes |
|---|---|---|
0 0 1 * * | Midnight on the 1st of every month | Equivalent to @monthly. |
0 3 1 * * | 03:00 on the 1st | Monthly billing or archival run. |
0 0 15 * * | Midnight on the 15th | Mid-month. |
0 0 1,15 * * | 1st and 15th | Twice-monthly payroll pattern. |
0 0 28 * * | The 28th of every month | The last day that exists in every month, February included. |
0 0 1 */3 * | The 1st of every third month | January, April, July, October. |
0 9 1-7 * 1 | Not "the first Monday" | This runs on days 1-7 and on every Monday, because of OR logic. See below for the correct form. |
0 0 L * * | Last day of the month | Quartz and some extended dialects only. Standard Unix cron rejects L. |
Running on the last day of the month in standard cron
Because Unix cron has no L, the portable trick is to run daily and let the command decide whether today is the last day:
0 23 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/month-end.sh
The schedule limits cron to the four candidate days, and the shell test lets exactly one of them through. The \% is escaped on purpose: inside a crontab, an unescaped % is turned into a newline and everything after it is fed to the command on standard input.
Running on the first Monday of the month
The same approach works here: restrict day of month to the first week, leave day of week as *, then guard in the shell so only the Monday qualifies:
0 9 1-7 * * [ "$(date +\%u)" = "1" ] && /usr/local/bin/first-monday.sh
Only days 1-7 are candidates, and date +%u returns 1 only on Monday, so exactly one day a month qualifies. In Quartz you would write this directly as 0 0 9 ? * MON#1.
Quarterly and yearly
| Expression | Runs | Notes |
|---|---|---|
0 0 1 1,4,7,10 * | The 1st of each quarter | Calendar quarters: January, April, July and October. |
0 0 1 2,5,8,11 * | Quarters offset by one month | For fiscal years starting in February. |
0 0 1 */6 * | Twice a year | January and July. |
0 0 1 1 * | Midnight on 1 January | Equivalent to @yearly or @annually. |
0 0 31 12 * | Midnight on 31 December | Year-end close. |
0 2 1 JAN,APR,JUL,OCT * | Quarterly at 02:00 | Month names, where supported. |
Special strings
Most cron implementations accept a handful of shorthand strings in place of all five fields. They are easy to read and work across Vixie cron, cronie and systemd's cron compatibility, but not in every scheduler. Kubernetes CronJobs accept them, while AWS EventBridge does not.
| String | Equivalent | Meaning |
|---|---|---|
@yearly | 0 0 1 1 * | Once a year at midnight, 1 January. @annually is a synonym. |
@monthly | 0 0 1 * * | Midnight on the first of the month. |
@weekly | 0 0 * * 0 | Midnight on Sunday. |
@daily | 0 0 * * * | Midnight every day. @midnight is a synonym. |
@hourly | 0 * * * * | The top of every hour. |
@reboot | None | Once, when the cron daemon starts after a boot. It has no time-based equivalent and is not supported everywhere. |
Five examples that do not mean what they look like
These are the expressions that pass review and then behave unexpectedly in production. Each one is syntactically valid, which is why reading the computed run times matters more than reading the syntax.
1. 0 0 13 * 5: not Friday the 13th
When day of month and day of week are both restricted, standard cron runs when either matches. This fires on the 13th of every month and on every Friday, about five times a month (the 13th plus every Friday) instead of once or twice a year. To get only Friday the 13th, schedule 0 0 13 * * and guard on [ "$(date +\%u)" = "5" ] in the command.
2. * */2 * * *: not every two hours
The minute field is *, so this runs every minute of every second hour: 60 runs at 00:00-00:59, then 60 more at 02:00-02:59, and so on, for 720 runs a day. The intended expression is 0 */2 * * *.
3. 0 9-17 * * *: ends at 17:00, not 17:59
This one is correct as written, but the neighbouring case trips people up: */15 9-17 * * * runs through 17:45, because the hour range 9-17 includes the whole of the 17:00 hour. If you want coverage to stop at 17:00 exactly, the minute restriction has to do that work.
4. 0 0 31 * *: silently skips five months
February, April, June, September and November have no 31st, so a job scheduled on the 31st runs seven times a year instead of twelve. Use 28 if you want it every month, or the last-day-of-month pattern above.
5. */90 * * * *: invalid or truncated
A step larger than the field's range has no useful meaning. Depending on the implementation, cron either rejects the line outright or clamps it to something you did not intend. Cron cannot express "every 90 minutes" directly. The closest approximations are 0 */2 * * * or two separate lines such as 0 0,3,6,9,12,15,18,21 * * * plus 30 1,4,7,10,13,16,19,22 * * *.
One page per schedule
Every schedule above also has a dedicated page with live next-run times, usage notes and the trap specific to it. Browse them in the schedule reference.
Build your own
If none of these is quite right, compose the schedule field by field in the visual builder and read the next five run times before you commit it. That is the fastest way to catch a wrong schedule while it is still cheap to fix. To decode an expression you inherited from someone else's config file, paste it into the Explainer.