Cron Expression Syntax, Explained by Field
Five fields, nine special characters, a dozen edge cases. A complete reference for cron syntax, minute, hour, day, month, weekday, with annotated real-world examples.
On this page β
Cron has been running scheduled jobs since 1975. The expression format has barely changed. Yet "cron syntax" is one of the most-Googled things by engineers who write it a dozen times a year, because the field order is counterintuitive, the edge cases are many, and the difference between implementations is silently wrong.
This is the reference you can stop Googling.
The Cron Builder on this site parses any expression and shows the next 10 scheduled runs, the human-readable explanation, and flags implementation differences. Use it while reading this.
The five-field format
ββββββββββββββ minute (0-59)
β ββββββββββββ hour (0-23)
β β ββββββββββ day of month (1-31)
β β β ββββββββ month (1-12 or JAN-DEC)
β β β β ββββββ day of week (0-7 or SUN-SAT, where 0 and 7 = Sunday)
β β β β β
* * * * *
A cron expression is executed when all five fields match the current time, with one notable exception for day-of-month / day-of-week (covered below).
Field reference
Minute (0-59)
0 β exactly on the hour
30 β at :30 past each hour
*/15 β every 15 minutes (0, 15, 30, 45)
5,20 β at :05 and :20 past each hour
Hour (0-23)
0 β midnight (12:00 AM)
9-17 β every hour from 9 AM to 5 PM
*/6 β every 6 hours (0, 6, 12, 18)
Day of month (1-31)
1 β first of the month
L β last day of the month (Quartz, not POSIX/vixie cron)
15,30 β 15th and 30th
Note: months have different lengths. A job scheduled on the 31st won't run in April, June, September, or November. A job on the 29th won't run every February. This is almost always a surprise when it first matters.
Month (1-12 or JAN-DEC)
1 β January (not 0)
*/3 β every quarter (January, April, July, October)
JAN,JUL β January and July (name aliases are case-insensitive in most impls)
Month is 1-indexed. This trips up programmers who are used to 0-indexed months from JavaScript's Date.getMonth().
Day of week (0-7 or SUN-SAT)
0 β Sunday (POSIX/vixie cron)
7 β Sunday (also valid in vixie cron, 0 and 7 are both Sunday)
1 β Monday
5 β Friday
MON-FRI β weekdays
The 0-or-7-for-Sunday quirk exists because the original POSIX spec used 0, but some early implementations also accepted 7, and vixie cron preserved both. Most modern cron implementations accept both. When in doubt, use the named form (SUN) to avoid ambiguity.
Special characters
| Character | Meaning | Example | Interpretation |
|---|---|---|---|
* | Any value | * * * * * | Every minute |
, | List | 1,15 (minute) | At :01 and :15 |
- | Range | 9-17 (hour) | Hours 9 through 17 inclusive |
/ | Step | */5 (minute) | Every 5 minutes |
L | Last | L (day of month) | Last day of month (Quartz only) |
W | Nearest weekday | 15W (day of month) | Nearest weekday to the 15th (Quartz only) |
# | Nth weekday | 2#3 (day of week) | Third Monday (Quartz only) |
? | No specific value | ? | Used in Quartz for day-of-month or day-of-week when the other is set |
The L, W, #, and ? characters are Quartz Scheduler extensions. They do not work in POSIX cron, vixie cron, or most Linux cron implementations. If you're writing crontab entries for a Linux server, stick to * , - /.
The day-of-month / day-of-week OR semantics
This is the most important edge case in all of cron:
If both day-of-month and day-of-week are set (not
*), most cron implementations run the job when EITHER condition is true, not both.
0 0 15 * 1 β runs on the 15th of every month
AND on every Monday, midnight
(NOT "only on Mondays that are the 15th")
This surprises virtually everyone who writes it for the first time. The intent is usually "the 15th of every month" but the result is "the 15th OR every Monday."
If you want "the 15th of every month only," use:
0 0 15 * *
If you want "the first Monday of each month," you need a workaround, cron doesn't express this natively. Common approaches:
- Use
0 0 1-7 * 1(any day from 1-7 that is also Monday): this relies on the OR semantics to coincidentally work, but only because 1-7 covers exactly the first week - Use a wrapper script that checks the date inside the job
The Quartz scheduler's ? character exists specifically to handle this: 0 0 15 * ? means "15th of every month, day of week not specified", removing the ambiguity.
Common expression examples
# Every minute
* * * * *
# Every hour, at :00
0 * * * *
# Every day at midnight
0 0 * * *
# Every day at 9 AM
0 9 * * *
# Every weekday at 8 AM
0 8 * * 1-5
# Every Sunday at 2 AM (for maintenance)
0 2 * * 0
# Every 15 minutes
*/15 * * * *
# Every 30 minutes, during business hours weekdays
*/30 9-17 * * 1-5
# First day of every month at midnight
0 0 1 * *
# Every quarter (Jan, Apr, Jul, Oct) on the 1st at midnight
0 0 1 1,4,7,10 *
# Twice a day, at 9 AM and 9 PM
0 9,21 * * *
@shorthand aliases
Most cron implementations support shorthand aliases that expand to standard expressions:
| Alias | Equivalent | Meaning |
|---|---|---|
@yearly or @annually | 0 0 1 1 * | Once a year, January 1st midnight |
@monthly | 0 0 1 * * | Once a month, first day midnight |
@weekly | 0 0 * * 0 | Once a week, Sunday midnight |
@daily or @midnight | 0 0 * * * | Once a day, midnight |
@hourly | 0 * * * * | Once an hour, at :00 |
@reboot | n/a | Once at system startup |
These are vixie cron extensions. They are not part of POSIX cron. They work on most Linux systems (systemd cron, Debian/Ubuntu cron, macOS cron) but not in AWS EventBridge, Kubernetes CronJobs, or Quartz.
Implementation differences to know
| Feature | POSIX/vixie | systemd | Quartz | AWS EventBridge | k8s CronJob |
|---|---|---|---|---|---|
| 5 fields | β | β | 6 fields* | β | β |
L, W, #, ? | β | β | β | Partial | β |
| Seconds field | β | β | β | β | β |
| Timezone config | Per-user CRON_TZ= | Per-unit OnCalendar= | Application config | Supported | 1.27+ |
@reboot | β | N/A | β | β | β |
*Quartz adds a seconds field at position 0, shifting all others right. Quartz expressions look like 0 0 9 * * ? (second minute hour dom month dow).
Validating your expression
Paste your expression into the Cron Builder. It shows:
- The human-readable explanation of the schedule
- The next 10 scheduled run times
- Which implementation quirks apply
Do this before deploying. A wrong cron expression runs silently, you won't know until the job misses or double-fires.
Further reading
- Cron Pitfalls: Timezones, DST, and Missed Runs: what happens when DST changes your schedule
- IEEE POSIX cron specification
- vixie cron man page
- Quartz Scheduler CronTrigger
Keep reading
Cron Pitfalls: Timezones, DST, and Missed Runs
Your cron job will run twice or skip entirely when DST changes. Here's why, how UTC solves it, and how to configure timezone-aware schedulers correctly.
AWS EventBridge Scheduler: Cron Schedules for Lambda and AWS Services
AWS EventBridge Scheduler runs Lambda functions, ECS tasks, and other AWS targets on a cron or rate schedule. Learn how to create schedules with cron expressions, handle...
Cron Expression Guide: Syntax, Fields, and Special Characters
Cron expressions schedule recurring jobs using five or six fields: minute, hour, day-of-month, month, day-of-week. Here's the full cron syntax including *, /, -, and ?...
Cron Job Scheduling: How Cron Works and Best Practices
Cron runs scheduled tasks using 5-field time expressions. Learn how cron daemons work, how to manage crontabs, timezone handling, error logging, and alternatives like systemd...
Cron Job Syntax: How to Write and Read Cron Expressions
Cron job syntax is five space-separated fields: minute, hour, day-of-month, month, day-of-week. Here's how to read and write cron expressions, with common schedule examples.
Cron Jobs in Next.js with Vercel Cron: Scheduled Functions
Run scheduled tasks in Next.js using Vercel Cron (serverless cron), GitHub Actions schedules, or Upstash QStash. Includes configuration, securing cron endpoints, and...
Cron Schedule Examples: Common Cron Expressions for Any Interval
Cron expressions schedule recurring jobs. Here's a reference of common cron schedules: every minute, hourly, daily, weekly, monthly, and business hours, with explanations for...
GitHub Actions Scheduled Workflows: cron Syntax and Examples
Schedule GitHub Actions workflows with cron expressions using the schedule trigger. Learn the cron syntax, timezone behavior (UTC only), avoiding missed runs, and examples for...
Kubernetes CronJob: Schedule Recurring Tasks in Kubernetes
Kubernetes CronJob runs containers on a cron schedule inside your cluster. Learn the CronJob spec, concurrency policy, job history limits, timezone support, and debugging...
Related tools
Cron Builder
Build and parse cron expressions with human-readable explanations.
Subnet / CIDR Calculator
Calculate IPv4 subnets, network, broadcast, usable range, wildcard mask. Input CIDR (/24) or dotted mask (255.255.255.0). Binary visualization.
Regex Tester
Test regular expressions with live match highlighting and explanation.
Timestamp Converter
Convert Unix timestamps, epoch seconds/milliseconds, and ISO 8601 dates.
Written by Mian Ali Khalid. More guides in Dev Productivity.