Cron Syntax Reference

Comprehensive reference for cron syntax reference covering essential concepts, practical examples, and production best practices.

Cron syntax defines when and how often a command or script runs on Unix-like systems. Use this reference when writing, debugging, or maintaining crontab entries—especially when jobs fail silently at 2:17 AM on a Tuesday, or when a daily backup misses a day due to a typo in the minute field.

Basic Cron Syntax

A cron entry consists of six fields: minute hour day-of-month month day-of-week command Each field uses a specific format, and all fields are space-separated.

# Example: Run backup at 2:17 AM every day
17 2 * * * /usr/local/bin/backup.sh

Run a Job at a Specific Time

Use fixed values in each field to schedule a job at an exact time.

# Run every Monday at 9:05 AM
05 9 * * 1 /usr/bin/notify-staff.sh

Common pitfall: Confusing day-of-week 1 (Monday) with month 1 (January). Silent failure: Using 1 in month field but expecting January, when job runs on 1st of every month instead.

Run a Job Every N Units of Time

Use */N to run a job every N units.

# Every 15 minutes
*/15 * * * * /usr/local/bin/check-service.sh
# Every 3 hours, starting at hour 0
0 */3 * * * /usr/local/bin/daily-report.sh

Edge case: */1 is equivalent to *, but */1 is explicit and useful in documentation.

Run a Job on Specific Days or Months

Use lists of values, separated by commas.

# Run every first of the month and every 15th
0 0 1,15 * * /usr/local/bin/monthly-accounts.sh
# Run on weekends and holidays (specific days)
0 8 * * 0,6 /usr/local/bin/weekend-report.sh

Confusion point: day-of-week uses 0 and 7 for Sunday. Best practice: Use 0,6 for weekends instead of 0,6,7. Silent failure: 0,6,7 in day-of-week implies Sunday + Saturday + Sunday again—overlapping days.

Use Ranges and Combinations

Combine ranges (N-M) with lists and step intervals.

# Run every weekday (Mon–Fri) at 9 AM and 4 PM
0 9,16 * * 1-5 /usr/local/bin/daily-work.sh
# Run every 10 minutes during business hours: 8 AM to 6 PM, Mon–Fri
*/10 8-18 * * 1-5 /usr/local/bin/business-hour-monitor.sh

Edge case: 1-5 includes 1,2,3,4,5 — not 1,2,3,4,5,6 for Mon–Sat. Common mistake: Writing 1-6 for Mon–Sat, but expecting 1-5 for Mon–Fri.

Run Jobs on Specific Month Names and Day Names

Use names instead of numbers for month and day-of-week.

# Run every first of the month, every spring month
0 0 1 Mar,Jun,Sep,Dec * /usr/local/bin/quarterly-report.sh
# Run every Friday at 2 PM in the winter months
0 14 * * Fri,Mon,Tue,Wed,Thu /usr/local/bin/winter-work.sh

Critical detail: Month names are case-insensitive. Silent failure: jan in month field matches January, but Jan also works. Best practice: Use full capitalized names (January, Saturday) for clarity in production crontabs.

Run a Job at a Specific Time in a Specific Month

Combine multiple conditions using lists and ranges.

# Run on the 1st and 15th of January, March, May, July, and September
0 0 1,15 Jan,Mar,May,Jul,Sep * /usr/local/bin/quarterly-billing.sh

Confusion: Jan,Mar,May,Jul,Sep in month field means “run every January, March, etc.” Edge case: 1,15 Jan,Mar means “1st and 15th of January and March only”.

Use Special Strings (Predefined Schedules)

Cron supports special strings in the first field (minute) to define common intervals.

# Run every minute
* * * * * /usr/local/bin/heartbeat-check.sh

# Run every hour
0 * * * * /usr/local/bin/hourly-maintenance.sh

# Run every day at midnight
0 0 * * * /usr/local/bin/daily-backup.sh

# Run every day at 1:00 AM
0 1 * * * /usr/local/bin/daily-sync.sh

# Run every week (Sundays at midnight)
0 0 * * 0 /usr/local/bin/weekly-report.sh

# Run every month (1st at midnight)
0 0 1 * * /usr/local/bin/monthly-summary.sh

# Run every year (1st January at midnight)
0 0 1 1 * /usr/local/bin/yearly-audit.sh

Key insight: * * * * * is the same as 0 * * * *, but * * * * * is more explicit for “every minute”.

Common error: Using 0 0 * * * for “daily” but forgetting that it runs every day at midnight, not every 24 hours. Sharp edge: 0 0 1 * * runs every month on the 1st, not every day at 1:00 AM.

Use Multiple Schedules in One Line

A single crontab entry can have multiple schedules by combining fields.

# Run at 2:17 AM every day, and 5:17 AM every weekday
17 2,5 * * 1-5 /usr/local/bin/daily-task.sh

Powerful pattern: Use 17 2,5 * * 1-5 to run a job at multiple times on weekdays.

Edge case: 2,5 in hour means 2 AM and 5 AM, not 2 and 5 PM. Common mistake: Writing 2,5 but expecting 2 PM and 5 PM.

Run Jobs with Complex Expressions

Combine lists, ranges, step, and names in a single field.

# Run every 10 minutes during business hours, every weekday
*/10 8-18 * * 1-5 /usr/local/bin/business-hour-monitor.sh
# Run every 15 minutes, but only on 1st, 15th, and 25th of the month
*/15 * 1,15,25 * * /usr/local/bin/quarterly-check.sh

Critical detail: */15 in minute field means every 15 minutes — not 15 minutes past the hour.

Best practice: Use 0 0 * * 1-5 for “run every Monday through Friday at midnight” Silent failure: Using 0 0 * * 1-5 but expecting a job that runs at midnight every weekday, but the job runs at midnight every Monday through Friday, including weekends.

Advanced: Use @ Predefined Schedules

The @ symbol simplifies common cron schedules.

# Run every 30 minutes
@every30min /usr/local/bin/monitoring-check.sh

# Run every 5 minutes
@every5min /usr/local/bin/health-check.sh

# Run every day at 8 AM
@daily /usr/local/bin/daily-report.sh

# Run every week on Monday at 8 AM
@weekly /usr/local/bin/weekly-reminder.sh

# Run every month on the 1st at 8 AM
@monthly /usr/local/bin/monthly-summary.sh

# Run every year on January 1st at 8 AM
@yearly /usr/local/bin/yearly-audit.sh

# Run every 10 minutes
@every10min /usr/local/bin/ten-minute-check.sh

Configuration: @everyNmin, @everyNhour, @everyNday, @everyNweek, @everyNmonth, @everyNyear.

Edge case: @every30min is equivalent to */30 * * * * Best practice: Use @daily instead of 0 0 * * * for clarity.

Silent failure: @weekly runs on Monday at midnight, but @weekly in crontab uses 0 0 * * 1 — not 0 0 1 * *. Sharp edge: @monthly uses 0 0 1 * *, but @monthly in crontab expects 0 0 1 * * — so @monthly is not 0 0 1 * * but 0 0 1 * * with a default 0 0 1 * *.

Common Failures and Debugging Tips

Ensure the command includes absolute paths. backup.sh in crontab may fail if PATH is not set.

# Common crontab setup with PATH
PATH=/usr/local/bin:/usr/bin:/bin
SHELL=/bin/bash
[email protected]

# Job with relative paths
0 2 * * * backup.sh

Redirect output and errors:

# Log all output and errors
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

Check day-of-week and day-of-month for overlap. Use 0 0 * * * for daily, but ensure crontab is installed and cron is running.

Check timezone: crontab runs in system timezone, not user’s timezone. Use TZ=America/New_York in crontab to set timezone.

# Set timezone for crontab
TZ=America/New_York
0 8 * * * /usr/local/bin/ny-report.sh

Use absolute paths. crontab does not inherit PATH from shell.

Check that cron is running: systemctl status cron Check logs: /var/log/cron or journalctl -u cron

Use crontab -e and crontab -l to verify.

Summary of Key Rules

Use this reference to write, read, and debug cron jobs with confidence.

This page was rewritten on 10 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.