Cron Expressions Explained: Complete Syntax Guide
· 12 min read
π Table of Contents
Cron is the time-based job scheduler in Unix-like operating systems. If you need to run a script at midnight, back up a database every Sunday, clear temp files every hour, or send reports on the first of each month, cron is your tool. But its expression syntax β those cryptic strings like 0 */6 * * 1-5 β can be intimidating at first.
This guide demystifies cron expressions completely. You'll learn every field, every special character, see dozens of real-world patterns, and understand the timezone pitfalls that trip up even experienced developers. Whether you're scheduling backups, running maintenance scripts, or automating reports, mastering cron syntax is essential for any developer or system administrator.
Anatomy of a Cron Expression
A standard cron expression has five fields separated by spaces. Each field represents a unit of time, and together they define exactly when your job should run.
ββββββββββββββ minute (0-59)
β ββββββββββββ hour (0-23)
β β ββββββββββ day of month (1-31)
β β β ββββββββ month (1-12)
β β β β ββββββ day of week (0-6, Sun=0)
β β β β β
* * * * * command to execute
Each field can contain a number, a range, a list, a step value, or a wildcard. The beauty of cron is that these simple building blocks combine to create incredibly flexible scheduling patterns.
Some cron implementations support a sixth field for seconds, and a seventh for year, but the standard five-field format is universally supported and what you'll encounter in most Unix-like systems including Linux, macOS, and BSD variants.
The Five Fields in Detail
Understanding each field's range and behavior is crucial for writing correct cron expressions. Let's examine each one systematically.
| Field | Range | Special Characters | Example |
|---|---|---|---|
| Minute | 0-59 | * , - / | */15 (every 15 min) |
| Hour | 0-23 | * , - / | 9-17 (9 AM to 5 PM) |
| Day of Month | 1-31 | * , - / L W | 1,15 (1st and 15th) |
| Month | 1-12 or JAN-DEC | * , - / | 1-6 (Jan through Jun) |
| Day of Week | 0-6 or SUN-SAT | * , - / L # | 1-5 (Mon through Fri) |
Minute Field (0-59)
The minute field controls which minute of the hour your job runs. A value of 0 means the top of the hour, 30 means half past, and 59 is the last minute of the hour.
Common patterns include */5 for every 5 minutes, 0,30 for twice per hour, or 15 for quarter past every hour.
Hour Field (0-23)
Hours use 24-hour format where 0 is midnight, 12 is noon, and 23 is 11 PM. This is one of the most common sources of confusion for developers used to 12-hour AM/PM notation.
Business hours are typically represented as 9-17 (9 AM to 5 PM), while overnight maintenance might use 0-6 (midnight to 6 AM).
Day of Month Field (1-31)
This field specifies which day of the month to run. Valid values are 1 through 31, though not all months have 31 days. Cron handles this gracefully β if you specify day 31 in February, the job simply won't run that month.
The special L character means "last day of the month" and automatically adjusts for month length and leap years.
Month Field (1-12)
Months can be specified numerically (1 for January through 12 for December) or using three-letter abbreviations (JAN, FEB, MAR, etc.). The abbreviations are case-insensitive in most implementations.
Quarterly schedules often use patterns like 1,4,7,10 (January, April, July, October) or 3,6,9,12 for fiscal quarter ends.
Day of Week Field (0-6)
Days of the week range from 0 (Sunday) to 6 (Saturday). Some systems also accept 7 as Sunday for convenience. Three-letter abbreviations (SUN, MON, TUE, etc.) are also supported.
The most common pattern is 1-5 for weekdays (Monday through Friday), while 0,6 or 6,0 represents weekends.
Pro tip: When both day of month and day of week are specified (not wildcards), the job runs when either condition is met (OR logic), not both. This catches many developers off guard. For example, 0 0 13 * 5 runs on the 13th of every month and every Friday, not just Friday the 13th.
Special Characters Explained
Special characters are what give cron expressions their power and flexibility. Each character serves a specific purpose in defining scheduling patterns.
Asterisk (*) - Wildcard
The asterisk means "every possible value" for that field. It's the most commonly used special character and appears in nearly every cron expression.
* * * * *β Run every minute of every day0 * * * *β Run at the top of every hour0 0 * * *β Run at midnight every day
Comma (,) - List Separator
Commas let you specify multiple discrete values. This is perfect when you need specific, non-consecutive times.
0 9,12,15,18 * * *β Run at 9 AM, noon, 3 PM, and 6 PM0 0 1,15 * *β Run at midnight on the 1st and 15th of each month0 0 * * 1,3,5β Run at midnight on Monday, Wednesday, and Friday
Hyphen (-) - Range Operator
Hyphens define inclusive ranges, making it easy to specify continuous periods.
0 9-17 * * *β Run every hour from 9 AM to 5 PM0 0 * * 1-5β Run at midnight Monday through Friday0 0 1-7 1 *β Run daily during the first week of January
Slash (/) - Step Values
The slash specifies step intervals, allowing you to run jobs at regular intervals within a range. The syntax is start/step or */step for the entire range.
*/15 * * * *β Every 15 minutes (0, 15, 30, 45)0 */2 * * *β Every 2 hours (0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22)0 0 */3 * *β Every 3 days (1st, 4th, 7th, 10th, etc.)0 9-17/2 * * *β Every 2 hours between 9 AM and 5 PM (9, 11, 13, 15, 17)
Quick tip: */15 doesn't mean "every 15 minutes starting now" β it means at minutes 0, 15, 30, and 45 of every hour. If you add a cron job at 10:07, a */15 pattern will first run at 10:15, not 10:22.
L - Last Day
The L character means "last" and is used in the day of month and day of week fields. It's particularly useful for month-end processing that needs to account for varying month lengths.
0 0 L * *β Run at midnight on the last day of every month0 0 * * Lβ Run at midnight on the last day of the week (Saturday)0 0 * * 5Lβ Run on the last Friday of every month
W - Nearest Weekday
The W character finds the nearest weekday to a given day of the month. If the specified day falls on a weekend, the job runs on the closest weekday instead.
0 0 15W * *β Run on the weekday nearest to the 15th0 0 1W * *β Run on the first weekday of the month0 0 LW * *β Run on the last weekday of the month
Hash (#) - Nth Day of Week
The hash character specifies the Nth occurrence of a weekday within a month. The syntax is day#occurrence.
0 0 * * 1#1β First Monday of every month0 0 * * 5#2β Second Friday of every month0 0 * * 3#4β Fourth Wednesday of every month
Note that L, W, and # are not supported in all cron implementations. They're available in modern versions like Vixie cron and most cloud-based schedulers, but may not work in older Unix systems.
Common Cron Patterns
Let's look at real-world scheduling patterns you'll use regularly. These examples cover the most common automation scenarios.
Every Minute, Hour, and Day
* * * * *β Every minute (use sparingly, can create load issues)0 * * * *β Every hour at minute 00 0 * * *β Every day at midnight0 12 * * *β Every day at noon
Multiple Times Per Day
0 0,12 * * *β Twice daily at midnight and noon0 */6 * * *β Every 6 hours (0:00, 6:00, 12:00, 18:00)0 8,12,16,20 * * *β Four times daily at specific hours*/30 * * * *β Every 30 minutes
Weekly Schedules
0 0 * * 0β Every Sunday at midnight0 0 * * 1-5β Weekdays at midnight0 9 * * 1β Every Monday at 9 AM0 0 * * 6,0β Weekends at midnight
Monthly Schedules
0 0 1 * *β First day of every month at midnight0 0 L * *β Last day of every month at midnight0 0 1,15 * *β 1st and 15th of every month0 0 1 */3 *β First day of every quarter (Jan, Apr, Jul, Oct)
Business Hours and Maintenance Windows
0 9-17 * * 1-5β Every hour during business hours (9 AM-5 PM, Mon-Fri)*/15 9-17 * * 1-5β Every 15 minutes during business hours0 2 * * *β 2 AM daily (common maintenance window)0 3 * * 0β 3 AM every Sunday (weekly maintenance)
| Use Case | Cron Expression | Description |
|---|---|---|
| Database backup | 0 2 * * * |
Daily at 2 AM |
| Log rotation | 0 0 * * 0 |
Weekly on Sunday midnight |
| Cache clearing | */10 * * * * |
Every 10 minutes |
| Monthly report | 0 9 1 * * |
First of month at 9 AM |
| Health check | */5 * * * * |
Every 5 minutes |
| Temp file cleanup | 0 */4 * * * |
Every 4 hours |
| SSL cert check | 0 6 * * 1 |
Every Monday at 6 AM |
| Quarterly audit | 0 0 1 1,4,7,10 * |
Jan 1, Apr 1, Jul 1, Oct 1 |
Advanced Scheduling Patterns
Once you've mastered the basics, these advanced patterns unlock sophisticated scheduling capabilities for complex automation scenarios.
Combining Ranges and Steps
You can combine ranges with step values to create precise scheduling windows:
*/5 9-17 * * 1-5β Every 5 minutes during business hours on weekdays0 8-18/2 * * *β Every 2 hours between 8 AM and 6 PM (8, 10, 12, 14, 16, 18)0 0 1-7 1 *β Daily during the first week of January
Complex List Combinations
Lists can include ranges and individual values mixed together:
0 0 1,15,L * *β 1st, 15th, and last day of every month0 9,12,15 * * 1-5β 9 AM, noon, and 3 PM on weekdays0 0 * 1,4,7,10 1β First Monday of each quarter
Avoiding Peak Hours
Schedule maintenance during off-peak times by excluding busy periods:
0 0-6,22-23 * * *β Every hour from midnight to 6 AM and 10 PM to midnight*/30 0-8,18-23 * * *β Every 30 minutes outside core business hours
Seasonal Schedules
Run jobs only during specific months or seasons:
0 0 * 6-8 *β Daily during summer months (June-August)0 0 * 12,1,2 *β Daily during winter months (Dec-Feb)0 0 15 11 *β November 15th (tax deadline reminder)
Payroll and Billing Schedules
Financial operations often require specific scheduling patterns:
0 9 15,L * *β 15th and last day of month at 9 AM (semi-monthly payroll)0 9 * * 5β Every Friday at 9 AM (weekly payroll)0 0 1 * *β First of month at midnight (monthly billing)0 0 1 1,4,7,10 *β Quarterly billing (Jan, Apr, Jul, Oct)
Pro tip: For critical financial operations, always add logging and alerting to your cron jobs. A missed payroll run is far worse than a noisy alert. Consider using a cron monitoring service like Cron Monitor to track execution and alert on failures.
Working with Crontab
The crontab (cron table) is where you define your scheduled jobs. Each user on a Unix system can have their own crontab, and there's also a system-wide crontab for administrative tasks.
Basic Crontab Commands
Managing your crontab is straightforward with these essential commands:
# View your current crontab
crontab -l
# Edit your crontab (opens in default editor)
crontab -e
# Remove your crontab entirely
crontab -r
# Edit another user's crontab (requires root)
sudo crontab -u username -e
Crontab File Format
Each line in a crontab file is either a comment (starting with #), an environment variable assignment, or a cron job. Here's a complete example:
# Set shell and path
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Email output to this address
[email protected]
# Daily backup at 2 AM
0 2 * * * /usr/local/bin/backup.sh
# Clear temp files every 6 hours
0 */6 * * * find /tmp -type f -mtime +7 -delete
# Weekly report every Monday at 9 AM
0 9 * * 1 /usr/local/bin/generate-report.sh
# Health check every 5 minutes (no email on success)
*/5 * * * * /usr/local/bin/health-check.sh > /dev/null 2>&1
Environment Variables
Cron jobs run with a minimal environment, which often causes scripts that work interactively to fail when run via cron. Set these variables at the top of your crontab:
SHELLβ The shell to use (default is/bin/sh)PATHβ Search path for commandsMAILTOβ Email address for job output (empty string disables email)HOMEβ Home directory for the jobLOGNAMEβ Username running the job
Output and Logging
By default, cron emails all output (stdout and stderr) to the user. Control this behavior with redirections:
# Send all output to a log file
0 2 * * * /path/to/script.sh >> /var/log/script.log 2>&1
# Discard all output
0 2 * * * /path/to/script.sh > /dev/null 2>&1
# Log only errors
0 2 * * * /path/to/script.sh > /dev/null 2>> /var/log/script-errors.log
# Email only errors (stdout discarded)
0 2 * * * /path/to/script.sh > /dev/null
System-Wide Crontabs
System crontabs in /etc/crontab and /etc/cron.d/ have a slightly different format with an additional user field:
# Format: minute hour day month weekday user command
0 2 * * * root /usr/local/bin/system-backup.sh
0 0 * * * www-data /usr/local/bin/clear-cache.sh
Most Linux distributions also provide convenience directories for common schedules:
/etc/c