Most cron schedules you will ever need are small variations on a few patterns: a step in the minute field for “every N minutes”, a fixed minute and hour for a daily job, and a restricted day-of-week or day-of-month field for weekly and monthly jobs. Rather than memorise syntax rules in the abstract, it is faster to keep a set of worked examples and adapt them. This article is that set. Each example is a complete five-field expression you can copy, with an explanation of the operator that makes it work so you can adjust the numbers with confidence.
What do the five fields mean again?
A cron line is five space-separated fields in a fixed order, followed by the command, and the fields are minute, hour, day of month, month, and day of week. Keeping this order in mind is enough to read every example below:
| Field | Position | Range |
|---|---|---|
| Minute | 1st | 0-59 |
| Hour | 2nd | 0-23 |
| Day of month | 3rd | 1-31 |
| Month | 4th | 1-12 |
| Day of week | 5th | 0-6 (0 = Sunday) |
Four operators do the work in every example: the star * matches every value, a slash makes a step (*/n = every n), a hyphen makes an inclusive range (1-5), and a comma makes a list (1,15). With those, the examples decode themselves.
How do I run a job every N minutes?
To run every N minutes, put a step in the minute field and leave the rest as stars. The step */N matches minute 0 and every Nth minute after it within the hour. These are the ones people look up most:
| Expression | Runs |
|---|---|
* * * * * |
Every minute |
*/5 * * * * |
Every 5 minutes (0, 5, 10, …) |
*/10 * * * * |
Every 10 minutes |
*/15 * * * * |
Every 15 minutes (0, 15, 30, 45) |
*/30 * * * * |
Every 30 minutes (0, 30) |
The common mistake is writing 15 * * * * when you mean every fifteen minutes. That expression has no slash, so 15 is a single value: it runs once an hour, at minute 15. The slash is what turns a value into an interval. Note also that steps restart every hour, so an interval that does not divide 60 evenly produces an uneven gap at the top of the hour. */40 fires at minute 0 and minute 40, then the counter resets, so the gap from 40 back to 0 is only 20 minutes. Stick to intervals that divide 60 (5, 10, 15, 20, 30) for even spacing.
How do I run a job every N hours?
Every N hours uses a step in the hour field, with the minute field pinned to a single value so the job runs once per matching hour rather than sixty times. If you leave the minute as a star, the job runs every minute of every Nth hour, which is almost never intended.
| Expression | Runs |
|---|---|
0 * * * * |
Every hour, on the hour |
0 */2 * * * |
Every 2 hours (0:00, 2:00, …) |
0 */6 * * * |
Every 6 hours (0, 6, 12, 18) |
30 */4 * * * |
Every 4 hours, at half past |
0 9-17 * * * |
Hourly during 9 AM to 5 PM |
The last row uses a range instead of a step: 9-17 matches every hour from 9 through 17 inclusive, so the job runs at the top of each hour across the working day. Combine a range with a step to thin it out, for example 0 9-17/2 * * * runs every second hour between 9 and 17.
How do I run a job once a day?
A daily job fixes both the minute and the hour and leaves the three date fields as stars, so it fires once at that time every day. Choose an off-peak hour for maintenance work:
| Expression | Runs |
|---|---|
0 0 * * * |
Every day at midnight |
0 3 * * * |
Every day at 3:00 AM |
30 6 * * * |
Every day at 6:30 AM |
0 12 * * * |
Every day at noon |
0 0,12 * * * |
Twice a day, midnight and noon |
The last example uses a comma list in the hour field: 0,12 matches both hour 0 and hour 12, so the job runs twice. Lists are the right tool when the times you want are not evenly spaced; a step could not produce exactly midnight-and-noon without also matching other hours.
How do I run a job weekly or on specific days?
A weekly job restricts the day-of-week field, the fifth field, to the day or days you want, while keeping a fixed minute and hour. Days are numbered 0 for Sunday through 6 for Saturday, and many cron implementations also accept three-letter names like MON.
| Expression | Runs |
|---|---|
0 9 * * 1 |
Mondays at 9:00 AM |
0 0 * * 0 |
Sundays at midnight |
0 9 * * 1-5 |
Weekdays at 9:00 AM |
0 18 * * 5 |
Fridays at 6:00 PM |
0 8 * * 1,3,5 |
Mon, Wed, Fri at 8:00 AM |
The business-hours pattern 0 9 * * 1-5 is one of the most-used cron lines in existence. Because only the day-of-week field is restricted here and the day-of-month field is a star, the schedule means exactly what it reads. That distinction matters, as the next section explains.
How do I run a job monthly or yearly?
A monthly job restricts the day-of-month field, and a yearly job restricts the month field as well. Here the classic gotcha appears: when you restrict both the day-of-month and the day-of-week fields, most cron implementations combine them with OR, not AND, so the job runs when either matches.
| Expression | Runs |
|---|---|
0 0 1 * * |
Midnight on the 1st of each month |
0 0 1,15 * * |
1st and 15th of each month |
0 4 28 * * |
4:00 AM on the 28th monthly |
0 0 1 1 * |
Midnight on 1 January (yearly) |
0 0 1 */3 * |
1st of every 3rd month (quarterly) |
Each of these keeps at least one of the two day fields as a star, so the OR behaviour never fires. If you wrote something like 0 0 13 * 5 hoping for “Friday the 13th”, you would instead get the 13th of every month and also every Friday, because either condition triggers the run. Keep one day field as a star and your monthly and weekly schedules mean what they say.
How do I check an expression before it goes live?
Verify a cron expression by reading it back field by field and confirming the next few run times, ideally in a tool that translates it to plain English as you edit. The examples here cover the common cases, but the moment you combine operators or reach for the day fields together, it is easy to write something that looks right and fires at the wrong time. A client-side cron builder lets you assemble each field, see the schedule described in words, and preview upcoming run dates entirely in your browser, so you are not pasting internal script paths or hostnames from your command into a remote service just to check the timing. Get the schedule confirmed locally, then drop it into your crontab.
Cron becomes easy once you treat it as pattern-matching with four operators. Reach for a step when you want “every N”, a range for a contiguous span like business hours, a list for a few specific values, and a star for anything you do not want to constrain. Keep one day field open to avoid the OR trap, and the examples above will cover the overwhelming majority of schedules you will ever write.