Cron Job Syntax: Schedule Tasks Like a Pro
March 30, 2026 · 6 min read
Cron is the time-based job scheduler built into Unix-like systems. It runs commands or scripts at fixed times or intervals — backups at midnight, report generation every Monday, cache invalidation every 15 minutes. The syntax is compact but unintuitive at first glance. This guide makes it readable.
The Five-Field Format
┌───────────── minute (0–59) │ ┌─────────── hour (0–23) │ │ ┌───────── day of month (1–31) │ │ │ ┌─────── month (1–12 or JAN–DEC) │ │ │ │ ┌───── day of week (0–7 or SUN–SAT, 0 and 7 are both Sunday) │ │ │ │ │ * * * * * command to execute
Field Values
* any value (every minute, every hour, etc.) 5 specific value (exactly 5) 5,10,15 list of values (at 5, 10, and 15) 1-5 range (every value from 1 to 5, inclusive) */5 step (every 5th: 0, 5, 10, 15, ...) 1-10/2 range with step (1, 3, 5, 7, 9)
Common Schedules
# Every minute * * * * * # Every 5 minutes */5 * * * * # Every hour, on the hour 0 * * * * # Every day at midnight 0 0 * * * # Every day at 2:30 AM 30 2 * * * # Every Monday at 9:00 AM 0 9 * * 1 # Every weekday (Mon–Fri) at 8:00 AM 0 8 * * 1-5 # Every weekend at noon 0 12 * * 6,0 # First day of every month at midnight 0 0 1 * * # Every 6 hours 0 */6 * * * # Twice a day (noon and midnight) 0 0,12 * * * # Every 15 minutes between 9 AM and 5 PM on weekdays */15 9-17 * * 1-5
Special Strings
Most cron implementations support predefined shorthand strings:
| String | Meaning | Equivalent |
|---|---|---|
| @yearly / @annually | Once a year, Jan 1 midnight | 0 0 1 1 * |
| @monthly | First day of each month at midnight | 0 0 1 * * |
| @weekly | Every Sunday at midnight | 0 0 * * 0 |
| @daily / @midnight | Every day at midnight | 0 0 * * * |
| @hourly | Every hour, on the hour | 0 * * * * |
| @reboot | Once at startup | — |
Editing the Crontab
crontab -e # edit your crontab (opens in $EDITOR) crontab -l # list current crontab crontab -r # delete your crontab (be careful!) crontab -u alice -e # edit another user's crontab (root only) # System-wide crontabs (different format — includes user field) /etc/cron.d/my-job /etc/crontab
The format in /etc/crontab and /etc/cron.d/ adds a username field after the five time fields:
# /etc/cron.d/backup 0 3 * * * root /usr/local/bin/backup.sh
Output and Logging
By default, cron emails output to the local user. On most production servers there is no mail server, so jobs silently fail. Always redirect output explicitly:
# Discard all output 0 * * * * /path/to/script.sh > /dev/null 2>&1 # Log stdout and stderr to a file 0 * * * * /path/to/script.sh >> /var/log/myjob.log 2>&1 # Log with timestamp 0 * * * * date >> /var/log/myjob.log && /path/to/script.sh >> /var/log/myjob.log 2>&1
Environment Variables in Cron
Cron runs with a minimal environment — no PATH, no shell aliases, no .bashrc. Scripts that work in your terminal often fail in cron because commands are not found. Fix this by using absolute paths or setting PATH at the top of the crontab:
# At the top of crontab -e PATH=/usr/local/bin:/usr/bin:/bin SHELL=/bin/bash MAILTO="" # disable email output 0 * * * * python3 /home/alice/scripts/report.py
Testing Cron Jobs
The hardest part of cron is that you cannot easily test a schedule without waiting. A few strategies: set the schedule to * * * * * (every minute) during development, then fix it once it works. Run the command manually as the cron user (sudo -u www-data bash -c "/path/to/script.sh") to catch environment issues. Check /var/log/syslog or journalctl -u cron for execution logs.
Use the DateTime Tools on io9.me to verify your cron schedule lines up with the correct UTC times.