You've seen it before. You need to schedule a job to run every weekday at 7:30 AM, so you open a tab, search "cron expression weekdays", stare at five cryptic fields, and immediately second-guess yourself.
Is it 30 7 * * 1-5 or 30 7 * * MON-FRI? Does */15 mean every 15 minutes starting from zero, or every 15th minute? And why does the internet have seventeen different answers?
Cron expressions are one of those things that look like line noise the first hundred times and suddenly click on the hundred and first. This article skips the theory lecture and goes straight to the patterns you'll actually reach for — explained clearly, with copy-paste syntax ready to go.
The Five Fields (Say Them Out Loud Once)
Every standard cron expression is exactly five fields separated by spaces:
┌───────────── minute (0–59)
│ ┌─────────── hour (0–23)
│ │ ┌───────── day of month (1–31)
│ │ │ ┌─────── month (1–12)
│ │ │ │ ┌───── day of week (0–7, where 0 and 7 are both Sunday)
│ │ │ │ │
* * * * *
Read it left to right: minute → hour → day → month → weekday.
Drill that order into your head and half the confusion disappears. The other half disappears once you know what the special characters actually do.
Special Characters
| Character | Meaning | Example |
|---|---|---|
* |
Every possible value |
* * * * * = every minute |
, |
List of values |
0,30 * * * * = at :00 and :30 |
- |
Range of values |
0 9-17 * * * = every hour from 9 AM to 5 PM |
/ |
Step (every N) |
*/15 * * * * = every 15 minutes |
That's it. Four characters. Everything else is just combining them.
The Cheat Sheet
Every minute
* * * * *
You probably won't run jobs this frequently in production, but great for testing that your scheduler is alive.
Every 5 minutes
*/5 * * * *
The / means "every N units." So */5 in the minute field = 0, 5, 10, 15 ... 55. Works the same way in any field.
Every 15 minutes
*/15 * * * *
Classic for polling jobs, cache warming, or health checks you want more granular than hourly.
Every 30 minutes
*/30 * * * *
Or equivalently: 0,30 * * * *. Both hit :00 and :30 of every hour.
Every hour (on the hour)
0 * * * *
Note the 0 in the minute field. * * * * * is every minute. 0 * * * * is every hour at minute zero.
Every hour at :30
30 * * * *
Useful when you want to offset from other hourly jobs to spread load.
Every 6 hours
0 */6 * * *
Runs at midnight, 6 AM, noon, 6 PM.
Daily at midnight
0 0 * * *
Most common cron pattern in existence. Daily reports, log rotation, database backups.
Daily at 2 AM
0 2 * * *
2 AM is a popular "quiet hours" slot. Low user traffic, indexes done rebuilding.
Daily at 8:30 AM
30 8 * * *
Minute field first, then hour. Easy to flip — don't.
Weekdays only (Monday–Friday)
0 9 * * 1-5
The 1-5 in the weekday field means Monday through Friday. Run a standup digest, a daily business report, anything that shouldn't fire on weekends.
Weekdays at 9 AM and 5 PM
0 9,17 * * 1-5
Combining the comma list and the weekday range. Two fires per day, only on business days.
Weekends only
0 10 * * 6,7
Saturday and Sunday at 10 AM. Useful for batch jobs you want to avoid during business hours.
Every Monday at 9 AM
0 9 * * 1
Weekly summaries, reports, cleanup jobs. Day 1 = Monday.
First day of every month at midnight
0 0 1 * *
Monthly invoicing, reports, archiving. The 1 is in the day-of-month field (third position).
First Monday of the month
0 9 1-7 * 1
The 1-7 (first 7 days) combined with 1 (Monday) fires when both conditions are met — the first Monday of the month. Verify this with your cron implementation, as behavior can vary.
Specific date once a year (e.g., January 1st)
0 0 1 1 *
Midnight on the 1st of January. Happy New Year, cron job.
Day-of-Week Reference
| Value | Day |
|---|---|
| 0 or 7 | Sunday |
| 1 | Monday |
| 2 | Tuesday |
| 3 | Wednesday |
| 4 | Thursday |
| 5 | Friday |
| 6 | Saturday |
Both 0 and 7 are Sunday — a legacy quirk. Use whichever your tool accepts.
Month Reference
| Value | Month |
|---|---|
| 1 | January |
| 2 | February |
| 3 | March |
| ... | ... |
| 12 | December |
Some implementations accept JAN, FEB, MON, TUE, etc. as aliases. Check your platform's docs.
Quick Test: Can You Read These?
Before looking at the answers, try reading each expression aloud:
*/10 * * * *
0 0 * * 0
0 12 * * 1-5
0 0 1,15 * *
30 23 * * *
Answers:
- Every 10 minutes
- Every Sunday at midnight
- Noon on weekdays
- Midnight on the 1st and 15th of every month
- 11:30 PM every day
If you got those, you know cron.
If You Don't Want to Memorize All This
The honest truth: nobody remembers every pattern. Even experienced engineers double-check their expressions before deploying a job that runs monthly.
If you want a visual way to build and validate cron expressions without trial and error, AlertSleep's cron expression generator lets you select human-readable options (every weekday, first of the month, etc.) and generates the correct syntax automatically. Useful for the edge cases that are easy to get wrong.
Quick-Reference Summary Table
| Goal | Cron Expression |
|---|---|
| Every minute | * * * * * |
| Every 5 minutes | */5 * * * * |
| Every 15 minutes | */15 * * * * |
| Every 30 minutes | */30 * * * * |
| Every hour | 0 * * * * |
| Every hour at :30 | 30 * * * * |
| Every 6 hours | 0 */6 * * * |
| Daily at midnight | 0 0 * * * |
| Daily at 2 AM | 0 2 * * * |
| Daily at 8:30 AM | 30 8 * * * |
| Weekdays at 9 AM | 0 9 * * 1-5 |
| Every Monday at 9 AM | 0 9 * * 1 |
| First of month at midnight | 0 0 1 * * |
| Every Sunday at midnight | 0 0 * * 0 |
| January 1st at midnight | 0 0 1 1 * |
| Weekdays at 9 AM and 5 PM | 0 9,17 * * 1-5 |
One Last Thing
When you deploy a cron job, always verify the timezone your scheduler uses. A job set to 0 2 * * * on a UTC server fires at 2 AM UTC — which might be 9 PM, 6 AM, or some other local time depending on where your users are. Always check. Always document it in a comment next to your cron expression.
# Runs daily at 2 AM UTC (10 PM ET / 7 PM PT)
0 2 * * * /usr/local/bin/run-backup.sh
Future-you will thank present-you.
Found this useful? Save the summary table and never Google "cron expression weekdays" again.
Top comments (0)