Anatomy of a cron expression
Cron is a Unix daemon that runs commands on a schedule. It's been around since 1975 and its basic syntax barely changed. A cron expression has 5 space-separated fields:
โโโโโ minute (0-59)
โ โโโ hour (0-23)
โ โ โโโ day of month (1-31)
โ โ โ โโโ month (1-12)
โ โ โ โ โโโ day of week (0-6, 0=Sunday)
โ โ โ โ โ
* * * * * Special characters
- * โ any value.
* * * * *is every minute. - , โ list of values.
0 9,12,18 * * *at 9, 12 and 18. - - โ range.
0 9-17 * * *every hour from 9 to 17. - / โ step.
*/5 * * * *every 5 minutes.
Practical examples
0 0 * * *โ daily at midnight.*/15 * * * *โ every 15 minutes.0 9 * * 1-5โ Monday to Friday at 9 AM.0 0 1 * *โ first day of each month at midnight.0 0 * * 0โ every Sunday at midnight.30 14 * * 6โ every Saturday at 14:30.
Typical use cases
- Backups. Daily overnight when load is lowest.
- Automated reports. Generate and email a dashboard every Monday at 8 AM.
- Temp file cleanup. Wipe /tmp every hour.
- Processing jobs. Run analytics every night.
- Health checks. Ping endpoints every minute.
- API sync. Pull data every 15 minutes.
Common pitfalls
- Day-of-month AND day-of-week.
0 0 1 * 1is NOT "first of the month AND Monday." It's "first of the month OR Monday." The operator is OR when both are specified. - Time zone. Cron uses the server's time zone. If your server is UTC and you want 9 AM New York (UTC-5), use
0 14 * * *. - Cron users. In Linux, each user has their own crontab.
crontab -eedits the current user's;sudo crontab -eedits root's. - PATH and environment. Cron jobs run in a minimal environment. If your script depends on env vars, set them explicitly at the top.
Modern cron alternatives
Cron is alive and well, but more sophisticated alternatives exist. systemd timers on Linux offer integrated logging, dependencies, missed-run catch-up. GitHub Actions and GitLab CI support cron schedules running in cloud infrastructure. AWS EventBridge and Google Cloud Scheduler are managed options.
Validate before going live
A misplaced cron expression can hurt. If you meant "once a day at 1 AM" but typed 1 * * * * (at minute 01 of every hour), you got 24 runs instead of 1. Before pushing to production, verify the expression with a plain-English explainer and confirm the next run matches your expectation.