Cron Expressions Explained: Read & Write a Crontab
Cron is the quiet scheduler that runs most of the recurring jobs on the internet — backups, report emails, cache refreshes, cleanup tasks. The one thing that trips everyone up is its cryptic five-field schedule, like 0 2 * * 1. This guide teaches you to read and write any cron expression with confidence, with plenty of real examples.
What cron and a crontab are
Cron is a time-based job scheduler on Unix-like systems. A crontab ("cron table") is the list of jobs it should run, each with a schedule and a command. Every minute, cron checks the table and runs anything whose schedule matches the current time. It is how a server can, say, email you a summary every Monday at 2 AM without anyone being there to press a button.
To build and read schedules visually, use our Cron Expression Parser — it translates any expression into plain English and shows the next run times.
The five fields
A standard cron schedule has five fields, separated by spaces, in this order:
* * * * *
| | | | |
| | | | +-- Day of week (0-6, Sunday = 0)
| | | +---- Month (1-12)
| | +------ Day of month (1-31)
| +-------- Hour (0-23)
+---------- Minute (0-59)
Each field says "when, within this unit, should the job run." A * means "every" value of that field. So * * * * * means "every minute of every hour of every day" — once a minute, forever.
The special characters
| Symbol | Meaning | Example | Reads as |
|---|---|---|---|
* | Every value | * * * * * | Every minute |
, | A list of values | 0 8,12,18 * * * | At 8, 12 and 18:00 |
- | A range | 0 9-17 * * * | Every hour from 9 to 17 |
/ | A step/interval | */15 * * * * | Every 15 minutes |
You can combine them: 0 9-17/2 * * 1-5 means "every 2 hours between 9 and 17, Monday to Friday."
Reading an expression: a worked example
Take 30 2 * * 1 and read it field by field:
- Minute = 30 → at minute 30
- Hour = 2 → of the 2 AM hour
- Day of month = * → any day of the month
- Month = * → any month
- Day of week = 1 → but only on Monday
Put together: "At 02:30 every Monday." That is a classic schedule for a weekly backup or report.
Common schedules you can copy
| Expression | When it runs |
|---|---|
*/5 * * * * | Every 5 minutes |
0 * * * * | Every hour, on the hour |
0 0 * * * | Every day at midnight |
30 9 * * 1-5 | 09:30, Monday to Friday |
0 0 1 * * | Midnight on the 1st of every month |
0 0 * * 0 | Midnight every Sunday |
0 */6 * * * | Every 6 hours |
0 0 1 1 * | Once a year, on 1 January |
The day-of-month vs. day-of-week trap
This is the most misunderstood part of cron. When you set both the day-of-month and the day-of-week fields (neither is *), most cron implementations treat it as OR, not AND. So 0 0 13 * 5 runs on the 13th of the month or on every Friday — not only on Friday the 13th. If you need a precise rule, leave one of the two fields as * and test it with a cron parser before you rely on it.
Handy shortcuts and extensions
Many systems accept named shortcuts instead of five fields:
@hourly=0 * * * *@daily(or@midnight) =0 0 * * *@weekly=0 0 * * 0@monthly=0 0 1 * *@yearly(or@annually) =0 0 1 1 *@reboot= run once when the server starts
Some schedulers (Quartz, and many cloud platforms) add a seconds field at the front, making six fields, plus extras like ?, L (last) and # (nth weekday). Always check which flavour your platform uses.
Tips for reliable cron jobs
- Use absolute paths. Cron runs with a minimal environment, so
/usr/bin/php /home/user/app/cron.phpis safer than a bare command. - Mind the timezone. Cron usually runs in the server's timezone — know whether that is UTC or local. Our Timezone Converter helps you plan runs across zones, and times are often stored as a Unix timestamp under the hood.
- Capture output. Redirect to a log (
>> /path/log 2>&1) so a silent failure does not go unnoticed. - Prevent overlaps. Use a lock file so a slow job does not start a second copy before the first finishes.
- Test the expression first with a Cron Parser so you are certain of the next run times.
Frequently asked questions
What does * * * * * mean?
Every minute of every hour of every day — the job runs once a minute, continuously. It is rarely what you want in production; a step like */5 is more common.
Is Sunday 0 or 7 in cron?
Sunday is 0 in the standard, and many systems also accept 7 for Sunday. Day names like SUN and MON often work too.
How do I run a job every 15 minutes?
Use */15 * * * *. The /15 step on the minute field means "every 15th minute": at :00, :15, :30 and :45.
Why didn't my cron job run?
Common causes: a wrong path, a missing environment variable, no execute permission, the wrong timezone, or output errors you never saw because you did not log them. Add logging and test the schedule in a parser.
What timezone does cron use?
By default, the server's system timezone. On a server set to UTC, 0 0 * * * runs at midnight UTC — which may be a very different local hour for you.
The bottom line
A cron expression is just five fields — minute, hour, day-of-month, month, day-of-week — with four special characters (* , - /) to describe when a job should run. Once you can read the fields left to right, even complex schedules become obvious. Watch the day-of-month/day-of-week OR trap, mind your timezone, and always verify a new schedule with our Cron Expression Parser before you trust it in production.