Crontab Format & Syntax Explained (with Examples)
Updated Jun 2026 · originally published Dec 2009 · Tested on Ubuntu 24.04, Debian 12, RHEL 9, macOS 14
A crontab is a configuration file that tells the cron daemon which commands to run and when. Each line holds five time fields (minute, hour, day of month, month, day of week) followed by the command to run. cron is the standard task scheduler on Unix-like systems — Linux, the BSDs, Solaris, and macOS — running commands automatically in the background at fixed intervals.
This page is the complete crontab reference: the format and syntax field by field, the most-copied examples, special strings like @daily, the environment gotchas that cause most failures, and how to debug a job that won’t run.
What cron actually is
cron is a daemon started at boot from your init system. The name comes from
chronos, the Greek word for time. You can stop, start, or restart it through
your service manager — systemctl restart cron on Debian/Ubuntu, or
systemctl restart crond on RHEL/Fedora.
A crontab (cron table) is the file that holds your scheduled entries. You
never edit it directly — you use the crontab command, which validates your
changes before installing them.
Crontab restrictions
Whether you can use cron at all is controlled by two files:
- If
/etc/cron.allowexists, your username must be listed in it. - If only
/etc/cron.denyexists, you can use cron unless you’re listed in it. - If neither file exists, on most systems only root may use cron.
The allow/deny files contain one username per line. (Older systems keep these
under /usr/lib/cron/.)
Crontab commands
Set your preferred editor first, then use the four core commands:
export EDITOR=vi # or nano, emacs, etc.
| Command | What it does |
|---|---|
crontab -e | Edit your crontab (creates one if it doesn’t exist) |
crontab -l | List the contents of your crontab |
crontab -r | Remove your crontab entirely |
crontab -v | Show when you last edited it (limited support) |
To work with another user’s crontab, add -u: sudo crontab -u www-data -l.
How to read a crontab entry
Read the five fields left to right: minute, hour, day-of-month, month, day-of-week, then the command. So 30 2 * * 1 /backup.sh reads as “at 2:30 AM every Monday, run /backup.sh.”
Crontab format and syntax
The crontab format is five time fields plus a command. This is the layout every crontab entry follows:
* * * * * command
│ │ │ │ │
│ │ │ │ └─ day of week (0–6, Sunday = 0 or 7)
│ │ │ └─── month (1–12)
│ │ └───── day of month (1–31)
│ └─────── hour (0–23)
└───────── minute (0–59)
Crontab fields and columns explained
Each of the five columns controls one part of the schedule, read left to right:
| Field | Column | Allowed values |
|---|---|---|
| 1 | Minute | 0–59 |
| 2 | Hour | 0–23 |
| 3 | Day of month | 1–31 |
| 4 | Month | 1–12 (or Jan–Dec) |
| 5 | Day of week | 0–6 (Sun=0, or 7; or Sun–Sat) |
A * means “every valid value for this field.” Beyond *, each field accepts:
- Lists —
1,15,30(these specific values) - Ranges —
9-17(an inclusive range) - Steps —
*/15(every 15th value)
Step values (the */5 syntax)
Step syntax runs a job at regular intervals. */5 in the minute field means “every 5 minutes”; */2 in the hour field means “every 2 hours.” You can combine a step with a range too: 0-30/10 means every 10 units from 0 to 30.
*/5 * * * * /path/to/script.sh # every 5 minutes
0 */2 * * * /path/to/script.sh # every 2 hours, on the hour
Crontab examples (most-copied)
These are the crontab expressions people copy most often:
| Expression | Runs |
|---|---|
* * * * * | Every minute |
0 * * * * | Top of every hour |
30 2 * * * | Daily at 2:30 AM |
0 9 * * 1-5 | Weekdays at 9:00 AM |
0 0 1 * * | First of every month, midnight |
*/15 * * * * | Every 15 minutes |
A worked example — remove temp files every day at 6:30 PM:
30 18 * * * rm /home/someuser/tmp/*
Every hour
Keep the hour field as *. Set the minute to 0 to fire at the top of the
hour, or any minute to offset it:
0 * * * * /path/to/script.sh # top of every hour
15 * * * * /path/to/script.sh # 15 past every hour
Every minute
* * * * * /path/to/script.sh
Specific months or weekdays
# 00:30 on the 1st of January, June, and December
30 0 1 1,6,12 * /path/to/script.sh
# 8:00 PM every weekday in October
0 20 * 10 1-5 /path/to/script.sh
# Midnight on the 1st, 10th, and 15th of every month
0 0 1,10,15 * * /path/to/script.sh
For 75+ ready-to-use recipes grouped by task — backups, monitoring, log rotation, business-hours patterns — see the crontab examples cookbook.
Special strings: @daily, @reboot, and shortcuts
Most cron implementations accept named shortcuts in place of the five fields. They are easier to read than the numeric form and cover the common schedules:
| String | Equivalent | Runs |
|---|---|---|
@reboot | — | Once, at startup |
@yearly or @annually | 0 0 1 1 * | Once a year, midnight Jan 1 |
@monthly | 0 0 1 * * | First of the month, midnight |
@weekly | 0 0 * * 0 | Sunday, midnight |
@daily or @midnight | 0 0 * * * | Every day, midnight |
@hourly | 0 * * * * | Top of every hour |
@daily /home/user/scripts/cleanup.sh
@reboot /home/user/scripts/start-tunnel.sh
@reboot is the one worth remembering: it runs a job once each time the machine boots, which is handy for starting a process that has no service unit.
Crontab environment
This is the single most common reason a job “works in my shell but not in cron.” cron runs your command from your home directory under a minimal environment:
HOME=/home/your-user
LOGNAME=your-user
PATH=/usr/bin:/bin
SHELL=/bin/sh
Note what’s missing: cron does not source your .bashrc, .profile, or any
shell startup file. No aliases, no functions, no custom PATH. Two consequences:
- Use absolute paths for every command. Find them with
which docker,which node, etc. Tools in/usr/local/binor~/.local/binwon’t be found otherwise. - If you need your shell environment, source it explicitly inside the script
cron calls, or set
PATH=andSHELL=/bin/bashat the top of the crontab.
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 2 * * * /home/user/scripts/backup.sh
Disable email
By default cron emails the job’s output to the local user. To silence it, set
MAILTO to an empty string at the top of the crontab:
MAILTO=""
Set it to an address instead to route output somewhere you’ll actually see it.
Generate a log file
Redirect both stdout and stderr to a file so failures aren’t silent:
*/5 * * * * /path/to/script.sh >> /var/log/myjob.log 2>&1
The >> appends; use > to overwrite each run. The 2>&1 sends stderr to the
same place as stdout — and the order matters. >> file 2>&1 captures both;
2>&1 >> file does not. (For the full explanation, see
what 2>&1 means in shell.)
Crontab file location
User crontabs are stored — but don’t edit these directly, always use crontab -e:
- Debian / Ubuntu:
/var/spool/cron/crontabs/ - RHEL / CentOS / Fedora:
/var/spool/cron/ - System-wide:
/etc/crontaband the/etc/cron.d/directory
Note that /etc/crontab and files in /etc/cron.d/ use a different syntax —
they add a username field between the time fields and the command:
# /etc/crontab — note the extra "root" field
30 2 * * * root /path/to/script.sh
Why isn’t my cron job running?
Work through these in order — the first three catch most failures:
- Did cron fire it? Check the log:
journalctl -u cron --since "1 hour ago"(or-u crondon RHEL). No entry means the schedule is wrong or the crontab isn’t installed for that user. - Did the command succeed? Redirect output to a file (see above) and read it.
- Is it the PATH problem? See Crontab environment — this is the usual culprit.
- Is the script executable?
chmod +x script.sh, and confirm the shebang line. Windows line endings (\r\n) break the shebang — fix withdos2unix. - Right user?
crontab -eedits the current user’s crontab. Root’s is separate:sudo crontab -l. - The day-of-month / day-of-week trap? See the warning above.
For the full systematic walkthrough — SELinux, time zones, overlap prevention, and a copy-paste debug crontab — see the complete cron debugging checklist.
When not to use cron
cron is the right tool for simple, time-based jobs. If you need more, modern alternatives are worth knowing:
- systemd timers — dependency management, persistent jobs across reboots, randomized delays, and journaled output. Native on most current Linux distros.
- Kubernetes CronJobs — the same cron syntax, for containerized workloads, with concurrency policies and history limits.
- Cloud schedulers — AWS EventBridge Scheduler, GCP Cloud Scheduler, Azure Logic Apps — for serverless workloads.
Rule of thumb: if your job needs retries, monitoring, or dependencies on other jobs, you’ve outgrown cron.
Related crontab resources
Keep going with these hands-on references:
- 75+ Crontab Examples for Real-World Tasks — copy-paste entries for backups, log rotation, and more
- Crontab Generator — build a cron schedule visually, no syntax memorizing
- systemd Timers vs Cron — when to graduate from cron
Crontab reference books
Want a deeper, offline reference? Browse our shelf of Linux and DevOps books — the shell scripting and system administration titles cover cron, systemd, and automation in depth.