Understanding Cron Expressions: A Practical Guide with Examples
What Are Cron Expressions?
Cron expressions are strings that define schedules for recurring tasks. Named after the Greek word βchronosβ (time), they originated in Unix systems as a way to run commands at specified intervals. Today, cron-style scheduling is used everywhereβfrom Linux crontabs and Kubernetes CronJobs to cloud services like AWS EventBridge and GitHub Actions.
A cron expression tells a scheduler when to run a job, not what to run. Mastering cron syntax means you can precisely control when your backups happen, when reports are generated, or when your CI pipeline triggers.
You can parse and debug cron expressions interactively with the Cron Parser on CodeKit.
The Five-Field Format
The standard cron expression consists of five fields separated by spaces:
ββββββββββββββ minute (0β59)
β ββββββββββββββ hour (0β23)
β β ββββββββββββββ day of month (1β31)
β β β ββββββββββββββ month (1β12)
β β β β ββββββββββββββ day of week (0β6, where 0 = Sunday)
β β β β β
* * * * *
Each field specifies when the job should run in that time unit. An asterisk (*) means βevery possible valueβ for that field.
Field-by-Field Breakdown
| Field | Allowed Values | Description |
|---|---|---|
| Minute | 0β59 | Which minute of the hour |
| Hour | 0β23 | Which hour of the day |
| Day of month | 1β31 | Which day of the month |
| Month | 1β12 | Which month of the year |
| Day of week | 0β6 | Which day of the week (0 = Sunday) |
Some implementations also support a sixth field for seconds (0β59) at the beginning, and a few support year as a seventh field. But the five-field format is the universal baseline.
Special Characters
Cron expressions become powerful through their special characters, which let you express complex schedules compactly.
Asterisk (*) β Every Value
The wildcard matches all valid values for the field:
* * * * * β Every minute of every hour of every day
Comma (,) β List of Values
Separate individual values with commas to match specific points:
0 9,12,18 * * * β At minute 0 of hours 9, 12, and 18 (9 AM, noon, 6 PM)
Hyphen (-) β Range
Define a contiguous range of values:
0 9-17 * * * β At minute 0 of every hour from 9 AM to 5 PM
Ranges and lists can be combined:
0 9-12,14-17 * * * β At 9β12 AM and 2β5 PM
Slash (/) β Step Values
The slash defines a step interval within a range. The number before the slash is the starting point; the number after is the interval:
*/15 * * * * β Every 15 minutes (at 0, 15, 30, 45)
0 */2 * * * β Every 2 hours (at 0:00, 2:00, 4:00, ...)
0 9 */3 * * β Every 3 days at 9 AM
You can combine a starting value with a step:
30 9/2 * * * β Starting at 9:30 AM, then every 2 hours (9:30, 11:30, 13:30, ...)
Combined Examples
0,30 9-17 * * 1-5 β Every 30 minutes during business hours on weekdays
0 0 1 */3 * β At midnight on the first day of every quarter
Common Cron Patterns
Here are the schedules youβll use most often:
| Expression | Schedule |
|---|---|
* * * * * | Every minute |
*/5 * * * * | Every 5 minutes |
*/15 * * * * | Every 15 minutes |
0 * * * * | Every hour (at minute 0) |
0 */2 * * * | Every 2 hours |
0 9 * * * | Every day at 9 AM |
0 9 * * 1 | Every Monday at 9 AM |
0 9 * * 1-5 | Every weekday at 9 AM |
0 0 1 * * | First day of every month at midnight |
0 0 1 1 * | January 1st at midnight (yearly) |
0 6 * * 1-5 | 6 AM every weekday |
30 4 * * 0 | 4:30 AM every Sunday |
Special Strings (Shortcuts)
Many cron implementations support human-readable shortcuts:
| Shortcut | Expression | Meaning |
|---|---|---|
@yearly | 0 0 1 1 * | Once a year (Jan 1) |
@annually | 0 0 1 1 * | Same as @yearly |
@monthly | 0 0 1 * * | Once a month |
@weekly | 0 0 * * 0 | Once a week (Sunday) |
@daily | 0 0 * * * | Once a day (midnight) |
@midnight | 0 0 * * * | Same as @daily |
@hourly | 0 * * * * | Once an hour |
These shortcuts are supported by Vixie cron (the default on most Linux distributions), Spring, and many cloud schedulers. They are not part of the POSIX standard.
Platform Differences
Cron syntax varies across platforms. Being aware of these differences prevents subtle scheduling bugs.
Standard Linux (Vixie Cron)
- Five fields
- Day of week: 0β6 (0 and 7 both mean Sunday)
- Supports
@rebootto run once after system startup - Supports environment variable assignments before the expression
Spring / Quartz Scheduler
- Six or seven fields (adds seconds; optionally adds year)
- Day of week: 1β7 (1 = Sunday) or MONβSUN
- Supports
Lfor βlastβ (e.g.,Lin day-of-month means the last day of the month) - Supports
Wfor βnearest weekdayβ and#for βnth day of the monthβ (e.g.,6#3means the third Friday)
AWS EventBridge
- Six fields (adds year)
- Supports
L,W, and#like Quartz - Uses
?as a βno specific valueβ placeholder for day-of-month or day-of-week when one must be unspecified
GitHub Actions
- Uses a cron-like syntax with five fields
- Minimum interval is 5 minutes (shorter intervals are ignored)
- Runs on the default branch only
- Day of week: 0β6 (0 = Sunday)
Kubernetes CronJobs
- Standard five-field format
- Supports
@rebootand other shortcuts depending on the underlying cron implementation - The
startingDeadlineSecondsfield controls how late a missed job can still start
Debugging Cron Expressions
Cron bugs are notoriously hard to catch because they only manifest at specific times. Here are strategies to avoid and diagnose them.
1. Calculate Next Run Times
Always verify what your expression actually means by computing the next several execution times. A typo in one field can shift the schedule dramatically.
Use the Cron Parser to enter an expression and see the next N execution times instantly.
2. Watch Out for Day-of-Month and Day-of-Week Interaction
In standard cron, when both day-of-month and day-of-week are specified (neither is *), the job runs when either condition is met (OR logic, not AND). This is a common source of confusion:
0 0 13 * 5 β Runs on the 13th of every month AND every Friday (not just Fridays that fall on the 13th)
Some platforms (like AWS EventBridge) use ? to explicitly mark βno specific valueβ and avoid this ambiguity.
3. Timezone Matters
Cron expressions are evaluated in the timezone of the system running them. A job scheduled for 0 9 * * * runs at 9 AM local server time. If your server is in UTC but your team is in New York, 9 AM UTC is 5 AM Eastern.
Always document the expected timezone, and prefer UTC for server-side schedules to avoid daylight saving time surprises.
4. Daylight Saving Time Edge Cases
When clocks spring forward or fall back, scheduled jobs can be skipped or run twice. For example, 0 2 * * * in a timezone that springs forward from 2:00 AM to 3:00 AM will skip that execution. Conversely, falling back means the job runs twice.
Scheduling outside the 1:00β3:00 AM window avoids most DST issues.
5. Test with Dry Runs
Before deploying a cron job to production, log what it would do without actually doing it. This is especially important for destructive operations like database cleanup or file deletion.
Best Practices
- Use UTC: Schedule in UTC and convert for display. This eliminates timezone confusion.
- Add jitter: If multiple jobs share the same schedule, stagger them slightly (e.g.,
1,16,31,46 * * * *instead of*/15 * * * *) to avoid thundering herd problems. - Set a timeout: Always configure a maximum runtime. A job that hangs can accumulate and cause resource exhaustion.
- Log execution times: Record when each job starts and finishes. This data is invaluable for debugging missed or overlapping runs.
- Prefer simple expressions:
0 */6 * * *(every 6 hours) is easier to verify than0 0,6,12,18 * * *, even though theyβre equivalent.
Conclusion
Cron expressions are a compact, powerful way to define recurring schedules. The five-field format covers most needs, and the special characters (*, ,, -, /) let you express everything from βevery minuteβ to βthe third Friday of every other month.β The key to using cron reliably is understanding platform differences, being aware of timezone and DST edge cases, and always verifying your expressions before deploying them.
To quickly validate and visualize any cron expression, try the Cron Parser on CodeKitβit shows you the next execution times, field breakdowns, and a human-readable description of your schedule.