You set the nightly backup to run “at 2 AM”, checked it the next morning, and found it had run every minute from 2:00 to 2:59. Sixty backups and one full disk later, cron syntax seems worth learning properly. It only has five fields.
What cron is
Cron is the job scheduler built into Unix-like systems such as Linux and macOS. It runs commands or scripts at set times: database backups, log rotation, scheduled emails, scrapers and so on. CI systems, Kubernetes and cloud schedulers borrowed the same syntax.
A cron expression is the short string that says when a job runs. For example, 0 */6 * * 1-5 means “at minute 0 of every sixth hour, Monday to Friday”. That’s 00:00, 06:00, 12:00 and 18:00 on weekdays.
The five fields
A standard expression has five fields separated by spaces:
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-7, 0 and 7 are Sunday)
│ │ │ │ │
* * * * *Each field holds a single value, a range, a list, a step or an asterisk. Most implementations also accept names such as JAN or MON in the month and day-of-week fields.
Special characters
Asterisk (*)
Matches every value. * * * * * runs every minute. This is how the backup above went wrong: * 2 * * * means “every minute of the 2 AM hour”. What it needed was 0 2 * * *.
Slash (/)
Sets a step. */15 in the minute field runs at 0, 15, 30 and 45 past the hour. To start somewhere else, put a range before the step: 5-59/15 runs at 5, 20, 35 and 50. Some schedulers, such as Quartz, also accept the shorter 5/15.
Hyphen (-)
Sets a range. 1-5 in the day-of-week field is Monday to Friday. Ranges take steps too: 1-5/2 is Monday, Wednesday and Friday.
Comma (,)
Makes a list. 1,15 in the day-of-month field runs on the 1st and 15th. Lists can include ranges: 1,5,10-15.
Common schedules
* * * * * every minute
0 * * * * every hour, on the hour
0 0 * * * every day at midnight
0 9 * * 1 every Monday at 09:00
30 8 * * 1-5 every weekday at 08:30
0 0 1 * * the first day of every month at midnight
*/15 * * * * every 15 minutes
0 */6 * * * every 6 hours
0 2 * * 0 every Sunday at 02:00Many systems also accept shortcuts such as @hourly, @daily, @weekly, @monthly and @reboot (run once at startup).
Cron on different platforms
The five-field format is the common core, but platforms extend it. Spring and Quartz add a seconds field at the start, and AWS adds a year field at the end.
on:
schedule:
- cron: "0 6 * * 1-5"spec:
schedule: "*/30 * * * *"cron(0 12 * * ? *)0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1Differences worth checking in your platform’s docs:
- Time zone. crontab uses the server’s time zone. GitHub Actions and AWS EventBridge cron expressions use UTC. Kubernetes uses the controller’s time zone unless you set
timeZone. - Minimum interval. GitHub Actions runs scheduled workflows at most every 5 minutes, and runs can start late when load is high.
- Extra syntax. AWS requires
?in either the day-of-month or day-of-week field. Quartz numbers days of the week 1 to 7 starting on Sunday.
Why a job runs at the wrong time
Cron is almost never wrong. The expression just means something other than what you expected. Three common traps:
- Steps follow the field’s range, not today’s date.
0 0 */2 * *runs on the 1st, 3rd, 5th and so on, then the 31st and the 1st of the next month back to back. It is not “every two days from now”. - Day of month and day of week are combined with OR. In standard cron,
0 0 13 * 5runs on every 13th and every Friday, not only on Friday the 13th. - The time zone is not the one you assumed. A job set for
0 9 * * *on a UTC server runs at 09:00 UTC.
How to use the cron generator
- Open the cron generator and type an expression, or pick one of the presets such as “Every 5 minutes” or “Every weekday at 9 AM”.
- Read the plain-language explanation under the input, for example “At 9:00 AM, Monday through Friday.”
- Check the next 5 runs, shown in your browser’s time zone.
- Copy the expression into your crontab, workflow file or scheduler.
It runs in your browser and handles standard five-field expressions: numbers, *, ranges, lists and steps, including steps on a range such as 1-5/2. The next-run preview follows standard cron rules. Steps count from the start of the range, 7 counts as Sunday, and when both day fields are set, a day matching either one runs. That makes the preview a handy way to catch the traps above before they reach production.
Names like MON or JAN, @ shortcuts such as @daily, and seconds or year fields aren’t supported. Write those schedules out in numbers, or check them against your platform’s docs.
