What is cron?
A short reference on cron — the five-field expression syntax, how the fields combine, the aliases, the timezone footgun, and the differences between standard cron, crond, and modern systemd timers.
The one-line definition
Cron is a time-based job scheduler that has run on Unix systems since the late 1970s. A cron expression is a compact five-field string that specifies when a job should run. The Unix daemon that interprets these is cron (or, on most modern distributions, crond); modern alternatives like systemd timers do the same job with different syntax.
The five fields
A standard cron expression is five space-separated fields:
┌────────── minute (0–59)
│ ┌──────── hour (0–23)
│ │ ┌────── day of month (1–31)
│ │ │ ┌──── month (1–12 or JAN–DEC)
│ │ │ │ ┌── day of week (0–6 or SUN–SAT; 7 also Sunday)
│ │ │ │ │
* * * * * command-to-run
A job runs whenever the current time matches every non-wildcard field at the same moment. 0 2 * * 1 means "minute 0, hour 2, any day of month, any month, Monday" → runs every Monday at 02:00.
What each field accepts
Each field can be:
- A single number —
5 - A wildcard —
*(every value) - A range —
9-17(every value from 9 to 17 inclusive) - A list —
1,15,30(just these values) - A step —
*/15(every 15 units, starting from the lowest value) or0-30/5
Combining: 0,30 9-17 * * 1-5 means "at minute 0 and minute 30, between 09:00 and 17:00, any day of month, any month, Monday through Friday" → every half-hour during business hours on weekdays.
The @ aliases
Cron also accepts a few mnemonic aliases instead of the five-field syntax:
| Alias | Expands to | Meaning |
|---|---|---|
@yearly / @annually |
0 0 1 1 * |
Once a year on January 1st at 00:00 |
@monthly |
0 0 1 * * |
Once a month at midnight on the first |
@weekly |
0 0 * * 0 |
Once a week at midnight on Sunday |
@daily / @midnight |
0 0 * * * |
Once a day at midnight |
@hourly |
0 * * * * |
Once an hour at the top of the hour |
@reboot |
(no equivalent) | Run once at system startup (not all crons support it) |
The footguns
Timezone. Standard cron uses the system's local time. If your server is in UTC and you write 0 2 * * 1, it runs at 02:00 UTC. If you move the server to America/New_York without changing the expression, it runs at 02:00 local New York time. Daylight saving transitions cause 0 2 * * 1 to either skip a run (spring forward) or run twice (fall back) on the affected day. Modern alternatives (Kubernetes CronJobs, GitHub Actions, AWS EventBridge) let you specify a timezone explicitly; standard cron does not.
Day-of-month and day-of-week are OR'd, not AND'd. This is the most surprising thing about cron. 0 0 1 * 1 does NOT mean "midnight on the first of the month if that's also a Monday." It means "midnight on the first OR midnight on any Monday." The two day fields are combined with OR when both are non-wildcards. Use one or the other if you want a specific day.
Six-field cron. Some implementations (Quartz, Jenkins, AWS EventBridge, Spring Scheduler) accept a six-field variant with seconds in the first position. The semantics are otherwise the same. Standard Unix cron is always five fields. Check which one your platform uses before copying an expression.
Long jobs and overlap. Cron will start your job at the scheduled time even if the previous run hasn't finished. If */5 * * * * takes 7 minutes to run, you can end up with multiple instances running in parallel. Your job needs to handle that itself — typically with a lockfile or a flock wrapper.
Output and silence. Cron mails the job's stdout and stderr to the user it runs as. If that mail is not configured (it usually isn't on modern systems), failures are silent. Always redirect stderr to a log file or pipe to a monitoring system.
What cron is good at
- Periodic maintenance — backups, certificate renewals, log rotation, cache warming.
- Cleaning up databases on a predictable schedule — every weeknight at 03:00.
- Periodic data fetches — pull from an upstream API every 15 minutes.
What cron is bad at
- Sub-minute scheduling. Standard cron's resolution is one minute. Six-field variants get seconds.
- Anything with external triggers. Cron runs on a clock, not in response to events. For event-driven scheduling use a queue or a workflow engine.
- Distributed jobs. Cron is per-host. If you want exactly one of N hosts to run a job, you need an external coordination layer or a tool that handles distribution (Kubernetes CronJob, Nomad periodic jobs).
Modern alternatives
- systemd timers — superseded cron on most modern Linux distributions. Same idea, much more verbose syntax (and timezone-aware).
- Kubernetes CronJob — runs containers on a schedule across a cluster. Same five-field syntax, with explicit timezone support.
- GitHub Actions, Cloudflare Workers Cron Triggers, AWS EventBridge — cron syntax in a managed environment, no host to maintain.
All of them use a cron-style expression as the time specification. The expression is still the load-bearing piece of syntax everywhere.
Try it
The cron visualizer at /tools/cron takes any cron expression (five or six field, including the @ aliases), explains it in English, and shows the next ten execution times in any timezone. Useful for confirming that 0 9-17 * * 1-5 does what you think before you commit it.