Cron Expressions Mastered: A Complete Guide With Examples (2026)
Cron is the universal scheduler of Unix systems — but its syntax is famously dense and inconsistent. Master POSIX cron syntax, special characters, common presets, and how to debug "why did not my job run?" — with copy-pasteable examples.
Cron has been scheduling Unix jobs since 1975, and it's still the most widely-used scheduler in the world — embedded in Linux, macOS, BSDs, Kubernetes, AWS, GitHub Actions, and thousands of other systems. Yet its syntax remains notoriously opaque. One wrong asterisk and your nightly backup silently never runs.
This guide takes you from "what does this expression mean" to confidently writing any cron expression you need. By the end, you'll understand every special character, the standard POSIX 5-field format, and how to debug the inevitable "why didn't my job fire?" moment.
The Basic Syntax: 5 Fields of Time
A standard (POSIX) cron expression has 5 fields, separated by spaces, representing a schedule:
* * * * * command
│ │ │ │ │
│ │ │ │ └─── Day of week (0-7, Sunday=0 or 7)
│ │ │ └───── Month (1-12)
│ │ └─────── Day of month (1-31)
│ └───────── Hour (0-23)
└─────────── Minute (0-59)
Each field can be a single value, a range, a list, a step, or a wildcard. The combination of all five fields tells the cron daemon "execute this command at any time matching ALL of these constraints."
Field-by-Field Reference
Minute (0-59)
Which minute of the hour the job should fire.
0— top of the hour30— half past*— every minute (use cautiously)*/15— every 15 minutes (at 0, 15, 30, 45)
Hour (0-23)
Which hour of the day (using 24-hour clock).
9— 9 AM21— 9 PM*/2— every 2 hours9-17— 9 AM through 5 PM
Day of Month (1-31)
Which day of the month. Be careful with values that don't exist in all months (e.g., 31 means "fire on the 31st" — which is no day in February).
1— first of the month15— 15th of the month*— every day1,15— 1st and 15th
Month (1-12)
Which months the job runs.
*— every month1— January only1,4,7,10— quarterly (Jan, Apr, Jul, Oct)6-8— June through August (summer)
Day of Week (0-7)
Which day of the week. Sunday is 0 or 7 (both mean Sunday). Most Linux systems use 0-6.
0— Sunday1— Monday1-5— Monday through Friday (weekdays)0,6— weekends only
The Special Characters
Cron has five special characters that make expressions flexible:
* — Asterisk (Wildcard)
Matches every value in the field. * * * * * means "every minute of every hour of every day."
, — Comma (List)
Specifies a discrete list of values. 0,15,30,45 in the minute field means "fire at 0, 15, 30, and 45 minutes past the hour."
- — Hyphen (Range)
Specifies an inclusive range. 9-17 in the hour field means "9 AM through 5 PM."
/ — Slash (Step)
Specifies a step value. */15 means "every 15 units." This is the most commonly-misused special character — it works with a wildcard or range.
*/15in minutes = fire at 0, 15, 30, 450-30/5in hours = fire at 0, 5, 10, ..., 30 (every 5 hours from midnight to 6 AM)*/10in minutes is equivalent to0,10,20,30,40,50
L, W, # — Extensions (Not Standard Cron)
Most cron implementations (including standard vixie-cron) don't support these. They appear in Quartz Scheduler (Java), AWS CloudWatch Events, and some Kubernetes CronJob implementations. Check your specific cron's docs before using.
L— last day of month / last specific weekdayW— nearest weekday (e.g.,15W= nearest weekday to the 15th)#— nth weekday of month (e.g.,5#2= 2nd Friday of month)
50+ Real-World Examples (Copy-Paste Ready)
Every N Minutes / Hours
* * * * *— every minute*/5 * * * *— every 5 minutes*/10 * * * *— every 10 minutes*/15 * * * *— every 15 minutes (quarter-hour)*/30 * * * *— every 30 minutes (half-hour)0 * * * *— every hour, on the hour0 */2 * * *— every 2 hours0 */6 * * *— every 6 hours (4x daily)
Daily Jobs
0 0 * * *— midnight every day0 2 * * *— 2 AM every day (good for nightly backups)0 5 * * *— 5 AM every day30 3 * * *— 3:30 AM every day0 12 * * *— noon every day0 17 * * *— 5 PM every day (end of business)
Weekly Jobs
0 9 * * 1-5— 9 AM weekdays (Mon–Fri)0 17 * * 5— 5 PM every Friday0 8 * * 1— 8 AM every Monday (start of week)0 22 * * 0— 10 PM every Sunday (Sunday night recap)30 4 * * 6— 4:30 AM every Saturday
Monthly Jobs
0 0 1 * *— midnight on the 1st of every month0 2 15 * *— 2 AM on the 15th of every month0 9 1 1 *— 9 AM Jan 1 (yearly reset)0 0 1 1,4,7,10 *— midnight first day of each quarter0 3 L * *— 3 AM on the last day of every month (Quartz/AWS syntax, NOT standard cron)
Yearly / Annual
0 0 1 1 *— midnight, Jan 1 (annual reset)0 12 31 12 *— noon, Dec 31 (New Year's Eve)0 0 25 12 *— midnight, Dec 25 (Christmas)
Time Zones: The Silent Killer
Cron jobs almost always run in the system's local time zone. If your server is set to UTC but you wrote 0 9 * * * expecting "9 AM Pacific time," you'll fire at 9 AM UTC (which is 1 AM or 2 AM Pacific, depending on DST).
Always verify:
- What time zone is the cron daemon running in?
- Does your expression match the local time zone or some other zone?
- Are DST transitions handled? (Most cron implementations handle DST by skipping or repeating the affected hour)
For multi-region systems, prefer storing cron expressions with explicit time zone prefixes (e.g., TZ=America/Los_Angeles 0 9 * * *) or convert to UTC yourself.
Common Cron Debugging Scenarios
Problem: "My job didn't fire!"
Checklist:
- Is the cron daemon running?
systemctl status cron(Linux) orlaunchctl list | grep cron(macOS). - Did you save the file? (
crontab -eauto-installs; direct edits to/etc/crontabneed a reload.) - What's in the system log?
grep CRON /var/log/syslogorjournalctl -u cron. - Does the cron user's environment include the paths your script needs? Cron has a minimal environment — use full paths or set them in the script.
- Is the script executable?
chmod +x /path/to/script. - Did the script's output go anywhere? Cron mails output to the user. Set
MAILTO=""if you don't want email, or redirect to a file.
Problem: "My job fires but fails silently"
Cron runs commands in a non-interactive shell. The usual culprits:
- Missing environment variables (PATH, HOME, etc.)
- No tty allocated (some commands prompt and hang)
- Working directory different from interactive shell
- Locale not set (causes issues with date/number parsing)
Debug by adding >> /tmp/cron-debug.log 2>&1 to your cron line to capture all output.
Problem: "Cron expression won't parse"
Common syntax errors:
- Forgot a field —
0 9 * * *has 5 fields;0 9 *won't parse. - Out-of-range values —
0 25 * * *is invalid (hours max 23). - Spaces where commas should be —
0 9 1, 15 * *has a stray space after comma. - Wrong step syntax —
*/15is correct,*/15minis not.
Cron vs Systemd Timers (Modern Alternative)
Modern Linux distributions often prefer systemd timers over cron. Advantages of systemd timers:
- Better logging (journalctl)
- Dependencies (can wait for network-online.target)
- Persistent across reboots (a missed job runs on next boot)
- More flexible scheduling (calendar expressions, monotonic)
Drawbacks:
- More verbose to configure
- Linux-only (won't work on macOS, BSD)
- Different mental model (need to learn .service + .timer files)
For new projects in 2026, systemd timers are often the right choice on Linux. For cross-platform or "run anywhere" needs (Heroku, Docker, Kubernetes), cron still wins.
Try It Yourself
Need a cron expression but don't want to remember the syntax? Use our free Cron Parser to decode any expression into plain English, with the next 10 fire times listed instantly.
Going the other way — you have a plain-English description ("every weekday at 9am") and need the expression? Use our Cron Expression Generator with our natural-language tool that generates the right cron expression from any description.
For reference, every modern Linux system ships with the cron daemon (vixie-cron or cronie). You can see your system's scheduled jobs with crontab -l for your user, or cat /etc/crontab for system-wide schedules.
About LaiUse
LaiUse is a free browser-based productivity platform with 178 tools across 12 categories. Every tool runs in your browser — your files never leave your device. Read more on our about page, or browse all free tools.