artisan.dev

Cron Syntax Cheatsheet: Fields, Operators and 25 Ready-Made Schedules

By Tahsin Abrar · Updated

Cron expressions pack a whole schedule into five short fields, which makes them compact and easy to get wrong. This cheatsheet covers the standard format used by Unix crontab, GitHub Actions, Kubernetes CronJobs and most job schedulers, followed by copy-ready examples and the mistakes that cause jobs to run at the wrong time — or not at all.

To check an expression as you read, open the Cron Expression Generator: it shows the next run times and a weekly heatmap of when the schedule fires.

Try itOpen the Cron Expression Generator — runs in your browser

The five 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 is also Sunday on most systems)
│ │ │ │ │
* * * * *  command

Fields are separated by spaces and read left to right from the smallest unit to the largest — except day-of-week, which sits at the end. Hours use the 24-hour clock, so 2 pm is 14.

Special characters

SymbolMeaningExampleReads as
*Every value* * * * *Every minute
,List0 9,17 * * *At 09:00 and 17:00
-Range (inclusive)0 9-17 * * 1-5On the hour, 09:00–17:00, Monday–Friday
/Step*/15 * * * *Every 15 minutes (:00, :15, :30, :45)
a-b/nStep within a range0 8-18/2 * * *Every 2 hours from 08:00 to 18:00

Steps count from the start of the range, not from when the job was installed. */7 in the minute field fires at :00, :07, … :56 and then again at :00 — a 4-minute gap at the top of the hour — because 60 is not divisible by 7.

Copy-ready schedules

ExpressionRuns
* * * * *Every minute
*/5 * * * *Every 5 minutes
*/15 * * * *Every 15 minutes
0 * * * *Every hour, on the hour
30 * * * *Every hour at half past
0 */2 * * *Every 2 hours
0 */6 * * *Every 6 hours (00:00, 06:00, 12:00, 18:00)
0 0 * * *Daily at midnight
0 9 * * *Daily at 09:00
30 18 * * *Daily at 18:30
0 9 * * 1-5Weekdays at 09:00
0 10 * * 6,0Weekends at 10:00
*/10 9-17 * * 1-5Every 10 minutes during business hours
0 0 * * 0Weekly, Sunday at midnight
0 8 * * 1Weekly, Monday at 08:00
0 0 1 * *Monthly, on the 1st at midnight
0 0 1,15 * *On the 1st and 15th of each month
0 12 15 * *Monthly, on the 15th at noon
0 0 1 */3 *Quarterly (Jan, Apr, Jul, Oct 1st)
0 0 1 1 *Yearly, on 1 January
0 3 * * 0Sunday 03:00 — a classic maintenance window
15 2 * * *Daily at 02:15 (off-peak, avoids :00 congestion)
0 0 28-31 * *Last few days of the month — pair with a date check (see below)
0 9 1-7 * 1Not "first Monday" — see the day-of-month gotcha
@dailyShortcut for 0 0 * * * (crontab only)

Shortcut macros

Vixie cron and its descendants (cronie on most Linux distributions) accept named shortcuts in place of the five fields: @yearly / @annually, @monthly, @weekly, @daily / @midnight, @hourly, and @reboot, which runs once when the cron daemon starts. GitHub Actions and Kubernetes support the time-based macros too, but many other schedulers do not, so the explicit five-field form is the portable choice.

Gotchas that bite in production

Day-of-month and day-of-week are OR-ed

When both day fields are restricted, standard cron fires when either matches. 0 9 1-7 * 1 therefore runs on days 1–7 of the month and on every Monday — not "the first Monday". To get the first Monday, schedule 0 9 * * 1 and have the script exit unless the date is 7 or less, e.g. [ "$(date +\%d)" -le 7 ] && ./job.sh in crontab.

Timezones

System cron uses the server's local timezone. GitHub Actions schedules always run in UTC. Kubernetes CronJobs use the controller's timezone unless you set spec.timeZone (for example "Asia/Dhaka"). Write the timezone next to the schedule in a comment so the next reader doesn't have to guess.

Daylight saving time

In zones with DST, a job scheduled between 01:00 and 03:00 can be skipped when clocks spring forward or run twice when they fall back, depending on the cron implementation. Schedule critical jobs outside that window, or run the server in UTC.

% in crontab commands

In a crontab line, an unescaped % is turned into a newline and everything after it is sent to the command as standard input. Escape it as \% — a common surprise with date +%Y-%m-%d.

A minimal environment

Cron runs jobs with a minimal PATH and without your shell profile. Use absolute paths to binaries and scripts, set required variables at the top of the crontab, and redirect output (>> /var/log/job.log 2>&1) so failures leave a trace.

Platform limits

  • GitHub Actions — the shortest supported interval is every 5 minutes, runs can start late during busy periods, and scheduled workflows in inactive public repositories are disabled after 60 days.
  • Seconds and ? — Quartz (Java/Spring) and AWS EventBridge use six or seven fields with a seconds or year field and the ?, L, W and # characters. Those expressions are not valid in standard crontab, and vice versa.

Writing it for different platforms

# crontab -e
*/15 * * * *  /usr/local/bin/sync.sh >> /var/log/sync.log 2>&1

# GitHub Actions (UTC)
on:
  schedule:
    - cron: '*/15 * * * *'

# Kubernetes CronJob
spec:
  schedule: "*/15 * * * *"
  timeZone: "Etc/UTC"

The Cron Expression Generator produces these snippets for crontab, GitHub Actions, Kubernetes and systemd timers from whatever schedule you build.

FAQ

What does */5 mean in cron?
*/5 is a step value: "every 5th value of this field, starting from the lowest". In the minute field it means minutes 0, 5, 10 … 55 — so every five minutes.
Is Sunday 0 or 7 in cron?
Both work in most implementations: 0 and 7 are Sunday, 1 is Monday and 6 is Saturday. Using 0 or SUN is the most portable choice.
Can cron run a job every 30 seconds?
Not with standard five-field cron — its smallest unit is one minute. Either run a script every minute that does its work twice with a 30-second sleep, or use a scheduler that supports seconds, such as systemd timers or Quartz.

More guides