How to Write CRON Expressions: A Complete Guide with Examples
CRON expressions define schedules for automated tasks. Learn the five-field syntax, special characters, common patterns, and how to avoid common pitfalls when writing CRON schedules for cron jobs, CI/CD pipelines, and cloud schedulers.
What Is a CRON Expression?
A CRON expression is a string of five (or six) fields that defines a recurring schedule. The cron daemon, originally created for Unix, reads these expressions to determine when to run scheduled commands.
CRON expressions are now used beyond Unix cron jobs — in GitHub Actions, AWS EventBridge, Kubernetes CronJobs, and virtually every cloud scheduler.
The Five-Field Syntax
┌───────────── 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, 0 = Sunday)
│ │ │ │ │
* * * * *
Special Characters
| Character | Meaning | Example |
|---|---|---|
* | Any value | * * * * * — every minute |
, | Value list | 0,30 * * * * — at 0 and 30 minutes past the hour |
- | Range | 0 9-17 * * * — every hour from 9am to 5pm |
/ | Step | */15 * * * * — every 15 minutes |
? | No specific value (day fields only) | 0 12 ? * MON — noon every Monday |
L | Last (some implementations) | 0 0 L * * — last day of month at midnight |
# | nth occurrence (some implementations) | 0 10 * * 1#2 — second Monday of the month |
Note: ? and L are not part of the POSIX standard but are supported by Quartz Scheduler (Java), AWS EventBridge, and GitHub Actions.
Common Patterns
# Every minute
* * * * *
# Every hour at minute 0
0 * * * *
# Every day at midnight
0 0 * * *
# Every day at 3:30am
30 3 * * *
# Every Monday at 9am
0 9 * * 1
# Every weekday at 9am (Monday–Friday)
0 9 * * 1-5
# Every 15 minutes
*/15 * * * *
# Every 6 hours
0 */6 * * *
# First day of every month at midnight
0 0 1 * *
# At midnight on the last day of the year (31 December)
0 0 31 12 *
# Every quarter (1st of Jan, Apr, Jul, Oct at midnight)
0 0 1 1,4,7,10 *
Day of Week Gotcha
Sunday is represented as both 0 and 7 in most implementations (POSIX uses 0–6, but 7 is also accepted for compatibility). However, 1 is Monday, which catches out developers used to the Date.getDay() JavaScript convention where 0 = Sunday and 1 = Monday — these happen to agree.
Six-Field and Seven-Field Variants
Some schedulers add fields:
- Seconds field (prepended) — used by Quartz Scheduler, Spring
@Scheduled, and some cloud services0 30 3 * * * ← second, minute, hour, day, month, weekday - Year field (appended) — rare, used in some enterprise schedulers
Always check which format your target platform expects.
GitHub Actions Schedule Syntax
GitHub Actions uses standard 5-field CRON with UTC timezone:
on:
schedule:
- cron: "0 3 * * 1" # 3am UTC every Monday
Gotcha: GitHub Actions does not guarantee exact execution at the scheduled time during high-load periods. Schedules may be delayed by several minutes.
AWS EventBridge Rate and Cron Expressions
AWS EventBridge supports both rate expressions and cron expressions. The cron format uses 6 fields (with ? required for day-of-month or day-of-week when specifying the other):
cron(0 12 * * ? *) # Every day at noon UTC
cron(0 9 ? * MON-FRI *) # Every weekday at 9am UTC
Note that AWS cron fields follow a slightly different order (minute hour day-of-month month day-of-week year) and require the ? wildcard in either the day-of-month or day-of-week field.
Timezone Considerations
Standard Unix CRON runs in the server's local timezone. This can cause problems when servers are in UTC but your schedule should follow a local business timezone (e.g., "9am London time" which shifts with BST).
Most modern schedulers allow specifying a timezone explicitly. For example, Kubernetes CronJob:
spec:
timeZone: "Europe/London"
schedule: "0 9 * * 1-5"
Always specify a timezone explicitly rather than relying on the server default.
Debugging Tips
- Use an online CRON visualiser (like DevGizmo's CRON Builder) to confirm your expression fires when expected
- Check the next 5–10 trigger times before deploying
- For
*/Nstep patterns, note that steps count from the minimum of the field, not from the first execution