A cron job is a command your computer runs on a schedule, by itself: a nightly database backup, a weekly log clean-up, a report every morning at nine. You describe the schedule once, in a short pattern of time fields, and the system does the rest.
Cron and cron jobs
Cron is a scheduler that has shipped with Unix-like systems for decades. It runs as a background service (a daemon, usually called cron or crond) that wakes up once a minute, reads its list of jobs and starts every job whose schedule matches the current time.
Each entry in that list is a cron job: a schedule plus the command to run. The list lives in a crontab, short for 'cron table'. Every user has their own, and you manage yours with the crontab command:
crontab -e # edit your crontab
crontab -l # print itCron doesn't care what the command is. It can be a shell script, a Python program or a curl call to an API. That makes it the usual answer to 'this has to happen every day, and nobody should have to remember to do it'.
Reading a cron expression
The schedule is a row of fields separated by spaces, each one a unit of time. The format the video uses has six fields, starting with seconds:
| Position | Field | Values |
|---|---|---|
| 1 | Second | 0-59 |
| 2 | Minute | 0-59 |
| 3 | Hour | 0-23 |
| 4 | Day of month | 1-31 |
| 5 | Month | 1-12 |
| 6 | Day of week | 0-7, 0 and 7 are Sunday |
A number pins a field to one value. An asterisk, *, means 'every' value of that field. The job runs at every moment where all the fields match at once, so the stars are what make it repeat: 0 0 * * * * pins the second and minute to zero and leaves everything else free, which means 'at the start of every hour'.
Five fields or six?
Classic Unix crontab, the one crontab -e edits, has only five fields. It starts at the minute, because the daemon only checks once a minute. Many schedulers built into frameworks and libraries, such as Spring's @Scheduled in Java and node-cron in Node.js, add a seconds field at the front, which gives the six-field form. Kubernetes CronJobs and GitHub Actions schedules use the five-field form.
Before you copy an expression from somewhere, check which form your tool expects. Paste an expression into a tool that expects the other form and it is either rejected or, worse, accepted with every value one field out of place, so the job runs at a time you never meant.
More than numbers and stars
Most cron implementations also understand:
- Lists:
1,15in the day-of-month field means the 1st and the 15th. - Ranges:
1-5in the day-of-week field means Monday to Friday. - Steps:
*/15in the minute field means every 15 minutes. - Shortcuts in classic crontab:
@hourly,@daily,@weekly, and@reboot, which runs once when the machine starts.
Common schedules
Here are some everyday schedules in the five-field crontab form. To use one in a six-field tool, put a 0 for the seconds in front.
| Expression | Runs |
|---|---|
0 * * * * | Every hour, on the hour |
30 2 * * * | Every day at 02:30 |
0 9 * * 1-5 | 09:00, Monday to Friday |
*/15 * * * * | Every 15 minutes |
0 3 1 * * | 03:00 on the 1st of each month |
Read an expression left to right and ask which fields are pinned and which are free. 30 2 * * * pins the minute and the hour and leaves the day, month and weekday free, so it runs at 02:30 on every day of the year.
A worked example: a nightly backup
Say you want a database backup every night at 02:30, and you only want to keep two weeks of them. Put the work in a script rather than in the crontab line itself:
#!/bin/sh
# /opt/jobs/backup.sh
set -e
day=$(date +%F)
pg_dump shop > "/backups/shop-$day.sql"
find /backups -name '*.sql' -mtime +14 -deleteThis dumps the shop database to a file named after today's date, then deletes backups older than 14 days. Make it executable with chmod +x /opt/jobs/backup.sh, then add one line to your crontab:
30 2 * * * /opt/jobs/backup.sh >> /opt/jobs/backup.log 2>&1The >> ... 2>&1 part appends everything the script prints, errors included, to a log file. Without it, cron tries to email the output to you, and on most servers that mail goes nowhere, so a failing job fails in silence. Once the line is saved you don't touch it again: the backup simply appears every morning.
Why a job works in your terminal but not in cron
This is the classic cron surprise. Cron runs your command in a much smaller environment than your login shell:
- A short
PATH. It is often little more than/usr/bin:/bin, so a program installed somewhere else isn't found. Use full paths, or setPATH=at the top of the crontab. - A plain shell. Commands run with
/bin/sh, and your.bashrcor.zshrcisn't loaded, so your aliases and exported variables are missing. - A different working directory. The job starts in your home directory, so relative paths may point somewhere you didn't expect.
%is special. In a crontab line, an unescaped%is turned into a new line. Writingdate +%Fstraight into the crontab breaks the command, which is one more reason to keep the logic in a script.
When a job misbehaves, the log file is the first place to look. If it is empty, check the system log for a line saying cron started the job at all.
Common mistakes
- A star where you meant a number.
* 2 * * *doesn't run at 2am. It runs every minute from 02:00 to 02:59, sixty times. Pin the minute as well:0 2 * * *. - Setting both day fields. In classic cron, when the day of month and the day of week are both restricted, the job runs when either matches.
0 9 1 * 1runs on the 1st of every month and on every Monday, not only on a Monday that falls on the 1st. - Forgetting the time zone. Cron uses the server's clock. A server set to UTC runs
0 9 * * *at 09:00 UTC, which may not be 09:00 where you are. Clock changes for daylight saving can also shift jobs scheduled in the small hours. - Overlapping runs. Cron starts a job on schedule whether or not the last run has finished. If a job that runs every five minutes sometimes takes ten, two copies run at once and can trip over each other. Wrap it in a lock, for example
flock -n /tmp/backup.lock /opt/jobs/backup.sh, so a second copy exits straight away. - Expecting missed runs to catch up. If the machine is switched off at 02:30, classic cron doesn't run the job later. Tools such as anacron, or systemd timers with
Persistent=true, exist for machines that aren't always on.
When to use it, and when not
Cron suits work that is regular, independent and fairly short: backups, clean-ups, reports, cache refreshes, pulling data from another system overnight.
It is a weaker fit when:
- You run several servers. A crontab lives on one machine. Put the same job on three web servers and it runs three times. Keep scheduled work on one host, or use a platform scheduler such as a Kubernetes CronJob, which creates one Job for each scheduled time, however many nodes the cluster has.
- The work should follow an event, not the clock. 'Send a receipt when an order is paid' belongs in the code that handles the payment, or on a queue, not in a job that checks for new orders every minute.
- You need retries, history and alerts. Cron starts a command and forgets about it. Job runners and workflow tools keep a record of every run and can retry a failure.
Key takeaways
- Cron is a scheduler; a cron job is one scheduled command inside it.
- A cron expression is a row of time fields: a number pins a field, and
*means 'every'. - Classic crontab has five fields starting at the minute; many libraries add seconds in front.
- Pin every field you care about, and send output to a log so failures are visible.
- Cron runs with a bare environment and doesn't prevent overlaps or catch up missed runs, so plan for both.