Developer11 min readUpdated 2026-08-26

What Is a Cron Job? Cron Syntax, Examples, and How to Write One

A cron job is a command your server runs automatically on a schedule you define. Back up a database every night, clear a cache every 15 minutes, email a report every Monday at 9am — that is cron. It has been the standard scheduler on Unix and Linux since the 1970s, and it is still what runs most of the internet's background work.

The whole thing is controlled by five numbers separated by spaces — that is the entire syntax. It is also why cron catches people out: five asterisks look simple until one wrong field turns a monthly job into an every-minute one.

This guide explains each field, gives you copy-paste expressions for the schedules people actually need, and covers the rule that silently breaks more cron jobs than any other — the day-of-month / day-of-week trap. If you would rather not hand-write it, our free Cron Expression Generator builds a valid expression from dropdowns in your browser.

What Is a Cron Job, Exactly?

Three words get used interchangeably but are not the same:

  • cron — the daemon that wakes every minute, checks what is scheduled, and runs it. The name traces to chronos, Greek for time.
  • crontab — the "cron table" file listing your jobs. Each user gets their own.
  • cron job — one line in that file: a schedule plus a command.

A cron job line has six parts — five schedule fields and then the command to run:

*  *  *  *  *  /path/to/command
│  │  │  │  │
│  │  │  │  └─ day of week  (0-7, Sunday is 0 or 7)
│  │  │  └──── month        (1-12)
│  │  └─────── day of month (1-31)
│  └────────── hour         (0-23)
└───────────── minute       (0-59)

An asterisk means "every", so * * * * * runs every minute of every day — the most common accidental setting there is.

The Five Cron Fields and Their Allowed Values

These ranges come straight from the crontab manual page (man 5 crontab):

PositionFieldAllowed valuesNotes
1stMinute0-59Minute past the hour
2ndHour0-2324-hour clock. Midnight is 0, not 24
3rdDay of month1-31Starts at 1, not 0
4thMonth1-12Or names: JAN-DEC
5thDay of week0-70 and 7 both mean Sunday. Or names: SUN-SAT

Two of these catch people out constantly: day of month starts at 1 while every other numeric field starts at 0, and day of week has eight valid values for seven days. Names work for months and weekdays (MON, FEB, case-insensitive), but ranges and lists of names are not portable — write 1-5, not MON-FRI.

The Five Special Characters

Every cron expression you will ever write is built from these:

CharacterNameMeaningExample
*AsteriskEvery possible value* * * * * = every minute
,CommaA list of specific values0 9,17 * * * = 9am and 5pm
-HyphenAn inclusive range0 9-17 * * * = hourly, 9am to 5pm
/SlashStep values — "every Nth"*/10 * * * * = every 10 minutes
namesThree-letterMonth or weekday abbreviations0 0 1 JAN * = 1 January

Steps can follow a range as well as an asterisk. 0-23/2 in the hour field means every second hour, which is the same as */2. And you can combine them freely: 0 8-18/2 * * 1-5 runs every two hours between 8am and 6pm, Monday to Friday.

One warning on steps: they divide the field's range rather than creating a rolling interval, so */40 is not "every 40 minutes" — see the FAQ below.

How to Write a Cron Expression in Five Steps

  1. Start with five asterisks: * * * * *. This runs every minute — you will now restrict it.
  2. Set the minute: 0 for on-the-hour, or a step like */15 for an interval. Leave * only if you want 60 runs an hour.
  3. Set the hour on a 24-hour clock — 9am is 9, 5pm is 17, midnight is 0.
  4. Set the day. Pick either day of month or day of week; leave the other as *. Setting both does not mean what you think — see the next section.
  5. Set the month (* unless the job is seasonal), then append the command with an absolute path.

Or skip the arithmetic: open the Cron Expression Generator, choose each field from a dropdown, and copy the finished expression. It runs entirely in your browser — nothing is sent to a server.

Cron Examples You Can Copy

The schedules people actually search for, ready to paste:

ExpressionWhen it runs
* * * * *Every minute
*/5 * * * *Every 5 minutes
*/10 * * * *Every 10 minutes
*/15 * * * *Every 15 minutes
0,30 * * * *Every 30 minutes (on the hour and half past)
0 * * * *Every hour, on the hour
0 */2 * * *Every 2 hours
0 0 * * *Every day at midnight
30 2 * * *Every day at 2:30am
0 9 * * 1-59am, Monday to Friday
0 9,17 * * 1-59am and 5pm on weekdays
0 0 * * 0Every Sunday at midnight
0 9 * * 6,09am on weekends
0 0 1 * *First day of every month, midnight
0 0 1 1 *Once a year, 1 January
0 8-18 * * 1-5Hourly during business hours, weekdays

Standard cron has no expression for "the last day of the month". Run it daily and let the script exit early unless tomorrow is the 1st.

The Shortcuts: @daily, @reboot and Friends

Instead of five fields you can use one of eight special strings. These are documented in the crontab manual and supported by most modern cron implementations:

ShortcutEquivalentMeaning
@rebootRun once, at startup
@yearly / @annually0 0 1 1 *Once a year
@monthly0 0 1 * *Once a month
@weekly0 0 * * 0Once a week
@daily / @midnight0 0 * * *Once a day
@hourly0 * * * *Once an hour

@reboot is the useful one — it has no five-field equivalent and is how you start a process at boot. It fires when cron starts, which is early in the boot sequence, so if your job needs the network or a database, add a sleep 30 or use a systemd unit instead.

The Day-of-Month / Day-of-Week Trap

This is the single most misunderstood rule in cron, and it will silently run your job far more often than you intended.

The two day fields are joined with OR, not AND. The crontab manual states it plainly: "If both fields are restricted (ie, are not *), the command will be run when either field matches the current time."

So this expression:

0 0 13 * 5

does not mean "midnight on Friday the 13th". It means midnight on the 13th of every month, plus midnight every Friday — roughly 64 runs a year instead of the one or two you wanted. The manual's own example makes the same point: 30 4 1,15 * 5 runs at 4:30am on the 1st and 15th of each month plus every Friday.

The rule in practice:

  • Restricting one day field and leaving the other as * behaves exactly as you expect.
  • Restricting both gives you the union of the two, not the intersection.
  • There is no cron syntax for the intersection. If you need "Friday the 13th", schedule 0 0 13 * * and have the script check the weekday itself before doing any work.

Dropdown-based builders make this easy to produce by accident. If your expression has a number in both day columns, set one back to *.

Installing a Cron Job: crontab -e, -l and -r

Writing the expression is half the job. Getting it into the crontab is the other half:

  1. Open your crontab for editing: crontab -e. The first run asks which editor you want; nano is the safe choice.
  2. Add your job on its own line, schedule first, then the command with absolute paths:
    0 3 * * * /usr/bin/php /var/www/html/backup.php
  3. Save and exit. In nano that is Ctrl+O, Enter, then Ctrl+X. Cron confirms with crontab: installing new crontab.
  4. Verify it landed: crontab -l lists every job for the current user.

Three more commands worth knowing:

  • crontab -l > backup.txt — save a copy before changing anything.
  • crontab -rdeletes your entire crontab with no confirmation and no undo. It sits one key from -e. Back up first.
  • sudo crontab -e -u username — edit another user's crontab.

End every line with a newline. Some cron implementations silently ignore a job on the last line without one.

Why Your Cron Job Is Not Running

The expression is usually fine. It is almost always the environment. In rough order of how often each one is the culprit:

  1. Relative paths. Cron does not start in your home directory and does not run your shell profile. Use absolute paths for the interpreter, the script, and every file the script touches: /usr/bin/python3 /home/me/job.py, not python3 job.py.
  2. A minimal PATH. Cron's PATH is typically just /usr/bin:/bin. Anything installed elsewhere — node via nvm, a Homebrew binary, a virtualenv — will not be found. Either use full paths or set PATH= at the top of the crontab.
  3. The script is not executable. Run chmod +x /path/to/script.sh, and make sure the file starts with a shebang such as #!/bin/bash.
  4. Unescaped percent signs. In a crontab % becomes a newline, and everything after the first one is fed to the command as stdin. This breaks date formats constantly — write date +\%Y-\%m-\%d, escaping each one.
  5. Output going nowhere. Cron emails output to the user, which on most servers is a black hole. Redirect instead: >> /var/log/myjob.log 2>&1 captures errors too, turning an invisible failure into a readable one.
  6. The wrong timezone. Cron uses the system timezone, usually UTC on cloud servers. Check with timedatectl. Our Timestamp Converter and Epoch Converter translate between UTC and local time — the Unix timestamp guide covers the conversions in depth.
  7. Cron is not running at all. Confirm with systemctl status cron (Debian/Ubuntu) or systemctl status crond (RHEL/CentOS).

To debug fast: set the job to * * * * * with logging on, wait two minutes, read the log. That tells you whether the schedule or the command is at fault — two very different fixes.

Cron Outside Plain Linux

The same five-field syntax turns up in a lot of places, with small but important differences:

  • cPanel / shared hosting (PHP). Most hosts expose a "Cron Jobs" page taking the same five fields. Point it at the PHP binary and an absolute path: /usr/local/bin/php /home/user/public_html/cron.php. Many enforce a 5- or 15-minute minimum interval.
  • systemd timers. The modern Linux replacement — more verbose, but they log to journalctl, handle dependencies, and can catch up on missed runs with Persistent=true, which cron cannot do.
  • Windows. No cron. Use Task Scheduler or schtasks. WSL includes cron but does not start it automatically.
  • AWS, Kubernetes and CI. EventBridge, Kubernetes CronJobs and GitHub Actions all accept cron expressions — but watch the dialects. EventBridge uses six fields and requires ? instead of * in one day field, which neatly sidesteps the OR trap above.
  • macOS. Cron works but is deprecated in favour of launchd.

Tips for Cron Jobs That Do Not Break

  • Always redirect output to a log. >> /var/log/job.log 2>&1 on every job. A cron job that has failed silently for six months is worse than no cron job.
  • Back up before editing. crontab -l > ~/crontab-backup.txt costs a second and survives a mistyped crontab -r.
  • Stagger your schedules. Eight jobs all firing at 0 0 * * * compete for the same disk. Spread them: 0:00, 0:07, 0:15.
  • Guard against overlap. A 5-minute job that sometimes takes 7 will run against itself. Wrap it: flock -n /tmp/job.lock /path/to/script.
  • Comment every job and test the command manually first — absolute paths and all — before scheduling it.
  • Avoid 1am-3am. Jobs in that window can be skipped or run twice when daylight saving shifts. Run the server in UTC if the timing matters.

Frequently Asked Questions

What does cron stand for?
It is not an acronym. The name is generally traced to chronos, the Greek word for time. Cron first appeared in Version 7 Unix in the 1970s and the syntax has barely changed since.
What is the difference between cron and crontab?
Cron is the background service that runs jobs. Crontab is both the file listing those jobs and the command used to edit it (crontab -e). Cron reads crontabs; crontabs do nothing on their own.
How do I run a cron job every 5 minutes?
Use */5 * * * *. That fires at minutes 0, 5, 10 and so on past every hour. The same pattern gives you any even interval — */10, */15, */30. Build it visually with the Cron Expression Generator.
Can a cron job run more often than once a minute?
No. One minute is cron's smallest resolution. For anything faster, run a job every minute that loops internally with sleep, or use a proper daemon or job queue instead.
Why does my cron job work in the terminal but not from cron?
Almost always the environment. Cron does not load your shell profile, so your PATH and environment variables are missing and the working directory is not what you expect. Use absolute paths and add >> /tmp/job.log 2>&1 to see the real error.
Does 0 0 13 * 5 mean Friday the 13th?
No — and this catches almost everyone. When both the day-of-month and day-of-week fields are restricted, cron runs the job when either matches. That expression fires on the 13th of every month and every Friday. Restrict only one day field, and let your script check the other condition.
What timezone do cron jobs use?
The system timezone, which on most cloud servers is UTC. Check it with date or timedatectl. Some cron implementations let you set CRON_TZ= at the top of the crontab. Use the Timestamp Converter to work out what your schedule means in local time.
How do I delete a cron job?
Run crontab -e, delete or comment out the line with #, then save. Avoid crontab -r — it wipes every job for the user with no confirmation and no undo.
What happens if the server is off when a job was scheduled?
Standard cron skips it entirely — there is no catch-up. If missed runs matter, use anacron (designed for machines that are not always on) or a systemd timer with Persistent=true.
Is */40 the same as every 40 minutes?
No. Step values divide the field's range rather than creating a rolling interval, so */40 fires at minute 0 and minute 40, then waits 20 minutes for the next hour. Only steps that divide evenly into 60 give even spacing.

Ready to try it?

Use the tool right now — free, no signup, no upload.