Toolmingo
Guides9 min read

Crontab Syntax: The Complete Cron Job Guide

Master cron job syntax with this complete crontab guide. Learn the five-field format, special strings, practical scheduling examples, crontab commands, environment variables, debugging tips, and common pitfalls — for Linux, macOS, and servers.

Cron is the built-in Linux/macOS task scheduler that runs commands at exact times — without you having to remember. Once you know the five-field format, scheduling any recurring task takes under a minute.

Quick reference

Expression Meaning
* * * * * Every minute
0 * * * * Every hour (at :00)
0 9 * * * Every day at 09:00
0 9 * * 1 Every Monday at 09:00
0 9 1 * * 1st of every month at 09:00
0 9 1 1 * January 1st at 09:00
*/15 * * * * Every 15 minutes
0 9,17 * * * At 09:00 and 17:00 daily
0 9 * * 1-5 Weekdays at 09:00
0 0 * * 0 Every Sunday at midnight
@reboot Once at system startup
@daily Once a day at midnight

The five-field format

Every cron expression has five fields separated by spaces, followed by the command to run:

┌─────────── minute (0–59)
│  ┌────────── hour (0–23)
│  │  ┌─────── day of month (1–31)
│  │  │  ┌──── month (1–12)
│  │  │  │  ┌─ day of week (0–7, 0 and 7 = Sunday)
│  │  │  │  │
*  *  *  *  *  command-to-run

Field values

Field Allowed values Special chars
Minute 0–59 * , - /
Hour 0–23 * , - /
Day of month 1–31 * , - / ? L
Month 1–12 (or JANDEC) * , - /
Day of week 0–7 (0 and 7 = Sunday, or SUNSAT) * , - / ? L

Special characters

Char Meaning Example
* Any value * * * * * — every minute
, List of values 0 9,13,17 * * * — 09:00, 13:00, 17:00
- Range 0 9 * * 1-5 — Monday through Friday
/ Step (every N) */15 * * * * — every 15 minutes
L Last 0 9 L * * — last day of month at 09:00
? No specific value Used in day fields when specifying the other

Special strings (@shortcuts)

These replace the five fields entirely:

String Equivalent Meaning
@reboot Run once at startup
@yearly / @annually 0 0 1 1 * Once a year, Jan 1 at midnight
@monthly 0 0 1 * * Once a month, 1st at midnight
@weekly 0 0 * * 0 Once a week, Sunday at midnight
@daily / @midnight 0 0 * * * Once a day at midnight
@hourly 0 * * * * Once an hour at :00
@reboot /home/ubuntu/start-app.sh
@daily  /usr/local/bin/db-backup.sh

Crontab commands

Edit your crontab

crontab -e          # edit your crontab (opens $EDITOR)
crontab -l          # list current cron jobs
crontab -r          # remove all your cron jobs (careful!)
crontab -u alice -e # edit another user's crontab (root only)

System-wide cron files

/etc/crontab             # system crontab (has extra "user" field)
/etc/cron.d/             # drop-in cron files (same format as /etc/crontab)
/etc/cron.daily/         # scripts run daily (no cron syntax needed)
/etc/cron.hourly/        # scripts run hourly
/etc/cron.weekly/        # scripts run weekly
/etc/cron.monthly/       # scripts run monthly

The system /etc/crontab format includes a username field:

# /etc/crontab
0 2 * * * root /usr/local/bin/nightly-backup.sh

Practical scheduling examples

Backups

# Database backup every night at 2:00 AM
0 2 * * * /usr/local/bin/db-backup.sh >> /var/log/backup.log 2>&1

# Weekly backup every Sunday at 3:30 AM
30 3 * * 0 /usr/local/bin/weekly-backup.sh

# Monthly archive on the 1st at midnight
0 0 1 * * tar -czf /backups/monthly-$(date +\%Y\%m).tar.gz /var/data

Log rotation / cleanup

# Delete log files older than 30 days, every night at 1 AM
0 1 * * * find /var/log/myapp -name "*.log" -mtime +30 -delete

# Truncate a log file every Monday morning
0 6 * * 1 > /var/log/myapp/debug.log

Application tasks

# Send a daily digest email at 8 AM
0 8 * * * /usr/bin/python3 /opt/myapp/send_digest.py

# Clear cache every 6 hours
0 */6 * * * redis-cli FLUSHDB

# Re-index search every Sunday at 4 AM
0 4 * * 0 curl -X POST https://api.example.com/reindex

# Run a Node.js script every 5 minutes
*/5 * * * * /usr/bin/node /home/ubuntu/scripts/poll.js >> /home/ubuntu/logs/poll.log 2>&1

System maintenance

# Sync time at midnight
0 0 * * * ntpdate pool.ntp.org

# Check disk space and alert if over 80%
*/30 * * * * df -h | awk '$5 > 80 {print}' | mail -s "Disk Alert" admin@example.com

# Start a service after reboot
@reboot /usr/sbin/nginx

Output and logging

By default, cron emails you the output. To redirect it:

# Redirect both stdout and stderr to a log file
0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

# Discard all output silently
0 2 * * * /usr/local/bin/backup.sh > /dev/null 2>&1

# Append timestamp to log
0 2 * * * echo "$(date): starting backup" >> /var/log/backup.log && /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

# Email output to a specific address (set MAILTO)
MAILTO=ops@example.com
0 2 * * * /usr/local/bin/backup.sh

Environment variables in crontab

Cron runs with a minimal environment — not your login shell. The PATH, HOME, and other variables you rely on may not be set.

# At the top of your crontab
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=ops@example.com
HOME=/home/ubuntu

# Or use absolute paths in every command
0 2 * * * /usr/bin/python3 /opt/app/script.py

Always use absolute paths for both the command and any files it references.


Escaping percent signs

The % character in a cron command is treated as a newline — it must be escaped with \%:

# Wrong — % is interpreted as newline
0 0 * * * tar -czf /backups/backup-$(date +%Y-%m-%d).tar.gz /var/data

# Correct — escape %
0 0 * * * tar -czf /backups/backup-$(date +\%Y-\%m-\%d).tar.gz /var/data

Debugging cron jobs

Check if cron is running

systemctl status cron     # Debian/Ubuntu
systemctl status crond    # RHEL/CentOS/Fedora
ps aux | grep cron

Check the cron log

grep CRON /var/log/syslog        # Ubuntu/Debian
grep CRON /var/log/cron          # RHEL/CentOS
journalctl -u cron               # systemd
journalctl -u cron | tail -50    # recent entries

Test your command manually

Always run the exact command from crontab manually in a fresh shell before scheduling it:

env -i HOME=/home/ubuntu PATH=/usr/local/bin:/usr/bin:/bin /bin/bash -c "your-command"

This simulates the minimal cron environment.

Common debugging checklist

  1. Absolute paths — is every path in the command absolute?
  2. Permissions — does the cron user have execute permission on the script?
  3. Script shebang — does your script start with #!/bin/bash (or the correct interpreter)?
  4. Line endings — scripts created on Windows have \r\n line endings that break Linux. Fix with dos2unix script.sh.
  5. Output logged — redirect 2>&1 so errors appear in your log, not just stdout.
  6. MAILTO set — set MAILTO="" to suppress emails if your mail isn't configured.

Common mistakes

Mistake Why it breaks Fix
Relative paths Cron's $PATH is minimal Use /usr/bin/python3, not python3
Unescaped % Cron treats % as newline Replace % with \%
Wrong day-of-week values Some crons treat 7 as Sunday, others don't Use 0 for Sunday; 1–7 or 0–6 work safely
Editing /etc/crontab directly without user field System crontab needs a username Add username: 0 2 * * * root /script.sh
Assuming login environment Cron has no .bashrc or .profile Set PATH explicitly at top of crontab
Both day-of-month and day-of-week set Cron uses OR logic (not AND) Set one to *; if both are non-*, either match triggers
No logging Hard to debug silently failing jobs Always redirect: >> /var/log/job.log 2>&1

Quick reference: timing patterns

Goal Expression
Every minute * * * * *
Every 5 minutes */5 * * * *
Every 15 minutes */15 * * * *
Every 30 minutes */30 * * * *
Every hour 0 * * * *
Every 2 hours 0 */2 * * *
Every day at midnight 0 0 * * *
Every day at 6 AM 0 6 * * *
Every weekday at 9 AM 0 9 * * 1-5
Every weekend at noon 0 12 * * 6,0
Every Monday at 8 AM 0 8 * * 1
First day of month at midnight 0 0 1 * *
Last day of month at 11 PM 0 23 L * *
Every 3 months (Jan/Apr/Jul/Oct) 0 0 1 */3 *
Once a year (Jan 1 at midnight) 0 0 1 1 *
At reboot @reboot

FAQ

What timezone does cron use? Cron uses the system timezone by default. To use a different timezone, set TZ=America/New_York at the top of your crontab. Check the system timezone with timedatectl or date.

Does cron run if the system was off at the scheduled time? Standard cron does not catch up on missed jobs. If your system was off at 2 AM, the 2 AM job simply doesn't run. Use anacron (or systemd timers with Persistent=true) if you need catch-up behaviour.

Why do my cron jobs work manually but not in cron? Almost always an environment issue — missing PATH, relative paths, or shell differences. Test with env -i ... /bin/bash -c "command" to simulate cron's environment.

How do I run a cron job as a different user? Edit the system crontab (/etc/crontab or a file in /etc/cron.d/) and include the username:

0 2 * * * deploy /usr/local/bin/deploy.sh

Can I run cron more often than once a minute? Standard cron's resolution is one minute. For sub-minute scheduling, use a loop inside the cron job (while true; do ...; sleep 10; done) or switch to systemd timers.

How do I verify a cron expression before using it? Use an online cron validator or test the job manually. The Unix Timestamp tool helps you verify exact run times by converting between human-readable dates and timestamps.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools