Cron is the scheduler that has quietly run the world's servers for decades, and its little strings of numbers and asterisks now show up everywhere — Linux boxes, GitHub Actions workflows, Kubernetes CronJobs, cloud schedulers. Once you can read a line like 0 9 * * 1-5 at a glance ("9am every weekday"), the whole thing stops being intimidating. This guide breaks down the syntax field by field, gives you a table of schedules you'll actually reuse, and covers the gotchas that cause jobs to fire at the wrong time — or never.
A standard cron expression is five space-separated fields, read left to right in increasing time span:
┌ minute (0-59)
│ ┌ hour (0-23)
│ │ ┌ day of month (1-31)
│ │ │ ┌ month (1-12)
│ │ │ │ ┌ day of week (0-6, Sun=0)
* * * * *
Each field says "run when the current time matches this." Five asterisks means "every minute of every hour of every day" — the most frequent standard schedule. You narrow it down by replacing asterisks with numbers or ranges. So 30 8 * * * reads as "at minute 30 of hour 8, on any day, any month, any weekday" — i.e. 8:30 every morning.
A quick note on the day fields: day-of-month and day-of-week are a little unusual. If you specify both as something other than *, most cron implementations run the job when either matches, not both — a frequent source of surprise.
| Expression | Meaning |
|---|---|
* * * * * | Every minute |
*/5 * * * * | Every 5 minutes |
0 * * * * | At the top of every hour |
0 9 * * * | Every day at 9:00 |
0 9 * * 1-5 | 9:00 on weekdays (Mon–Fri) |
0 0 * * 0 | Midnight every Sunday |
30 2 1 * * | 2:30 on the 1st of every month |
0 0 1 1 * | Midnight on January 1st (yearly) |
0 */6 * * * | Every 6 hours (00, 06, 12, 18) |
0 8,20 * * * | At 08:00 and 20:00 daily |
* — any value. Matches every value the field allows., — list. 1,15,30 in the minute field runs at minutes 1, 15 and 30.- — range. 1-5 in the weekday field means Monday through Friday./ — step. */15 means "every 15", i.e. 0, 15, 30, 45. You can combine it with a range: 0-30/10 is 0, 10, 20, 30.? — no specific value. Used in the day-of-month or day-of-week field in Quartz-style cron (Java, some cloud schedulers) to avoid the either/or ambiguity above. Standard Linux cron does not support ?.Many crons also accept nicknames like @daily, @hourly, @weekly and @reboot. They're readable, but note that @reboot is unrelated to a clock time — it runs once when the scheduler starts.
flock.anacron or a scheduler with catch-up semantics.Linux crontab. Run crontab -e to edit your user's jobs. Each line is a five-field expression followed by the command:
0 3 * * * /usr/bin/backup.sh
That runs the backup script at 3am daily. Because cron uses a minimal environment, always use absolute paths and redirect output (e.g. >> /var/log/backup.log 2>&1) so failures aren't silent.
GitHub Actions. The schedule trigger takes the same five-field syntax, in UTC, and the expression must be quoted:
on:
schedule:
- cron: '0 6 * * *'
One caveat worth knowing: scheduled GitHub Actions runs are best-effort and can be delayed during periods of high load, so don't rely on them for second-precise timing. For anything time-critical, a dedicated scheduler is safer.
Is Sunday 0 or 7? Sunday is 0 in most crons, and many also accept 7 for Sunday. Weekdays run 1 (Monday) to 6 (Saturday).
What's the difference between five and six fields? The classic Unix format has five fields (minute–weekday). Quartz-style cron (Java, some AWS services) adds a leading seconds field and a trailing optional year, giving six or seven.
Why didn't my job run? Usual suspects: wrong timezone, a relative path cron couldn't resolve, missing environment variables, or the file not being executable.
Can cron run every 30 seconds? Not directly — one minute is the floor. Workarounds include running the job every minute and having it sleep 30 seconds, or using a different scheduler.