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.

Comma (,) - List Separator

Commas let you specify multiple discrete values. This is perfect when you need specific, non-consecutive times.

Hyphen (-) - Range Operator

Hyphens define inclusive ranges, making it easy to specify continuous periods.

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.

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.

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.

Hash (#) - Nth Day of Week

The hash character specifies the Nth occurrence of a weekday within a month. The syntax is day#occurrence.

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

Multiple Times Per Day

Weekly Schedules

Monthly Schedules

Business Hours and Maintenance Windows

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:

Complex List Combinations

Lists can include ranges and individual values mixed together:

Avoiding Peak Hours

Schedule maintenance during off-peak times by excluding busy periods:

Seasonal Schedules

Run jobs only during specific months or seasons:

Payroll and Billing Schedules

Financial operations often require specific scheduling patterns:

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:

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: