What Is a Cron Expression? A Beginner's Guide
Suppose you want to run a PHP script every night, back up a database every day, send a report every Monday morning, or clean up temporary files every hour. Doing any of these manually is inconvenient and easy to forget. A cron job lets a system run a command automatically according to a schedule, without anyone triggering it by hand.
Cron is the time-based job scheduler commonly available on Linux and other Unix-like systems. The schedule itself — when the job runs — is written as a cron expression. The command that actually runs is separate from that. This distinction matters:
- Cron expression = the schedule (when to run)
- Cron command = the task to execute (what to run)
This guide focuses on the cron expression itself: the traditional five-field syntax, how to read one, common examples, and the mistakes that trip people up most.
What Is Cron?
Cron runs commands automatically at times you specify — a PHP script, a database backup, a job that deletes old log files, a scheduled report email, a cache refresh, an API call, a queue processor, a daily file export. It runs according to the system's configured time and timezone, which is covered in more detail later.
One thing worth being clear about from the start: a cron schedule only defines when the system should attempt to run a job. It doesn't guarantee the job finishes successfully — a script can still fail, hang, or error out after cron has correctly triggered it.
What Is a Cron Expression?
A traditional five-field cron expression defines a schedule using minute, hour, day-of-month, month, and day-of-week:
* * * * *
│ │ │ │ │
│ │ │ │ └── day of week
│ │ │ └──── month
│ │ └────── day of month
│ └──────── hour
└────────── minute
| Field | Allowed values | Meaning |
|---|---|---|
| Minute | 0–59 | Minute of the hour |
| Hour | 0–23 | Hour of the day |
| Day of month | 1–31 | Calendar day |
| Month | 1–12 | Month of the year |
| Day of week | 0–7 | Day of week, depending on implementation |
On that last row: both 0 and 7 commonly represent Sunday in traditional cron implementations (Kravoy's generator treats them as equivalent). Not every scheduler agrees on every detail of this syntax, though — check the specific system's documentation if you're unsure, especially outside plain Unix cron.
Understanding the Five Cron Fields
Minute (0–59)
15 * * * *
Runs at minute 15 of every hour — 00:15, 01:15, 02:15, and so on.
Hour (0–23)
0 2 * * *
Runs at 2:00 AM every day.
Day of Month (1–31)
0 9 1 * *
Runs at 9:00 AM on the first day of every month.
Month (1–12)
0 9 1 1 *
Runs at 9:00 AM on January 1st, once a year.
Day of Week
0 or 7 = Sunday, 1 = Monday, 2 = Tuesday, 3 = Wednesday, 4 = Thursday, 5 = Friday, 6 = Saturday.
0 9 * * 1
Runs at 9:00 AM every Monday. Some cron implementations also accept three-letter weekday names like MON, though the numeric form is the most universally supported.
Cron Special Characters
Asterisk * — matches every allowed value for that field.
* * * * *
Runs every minute.
Comma , — specifies multiple values.
0 9,18 * * *
Runs at 9:00 AM and 6:00 PM every day.
Hyphen - — defines a range.
0 9 * * 1-5
Runs at 9:00 AM, Monday through Friday.
Slash / — defines a step, or interval.
*/5 * * * *
Runs every 5 minutes.
0 */2 * * *
Runs every 2 hours, on the hour.
Common Cron Expression Examples
| Cron expression | Meaning |
|---|---|
* * * * * | Every minute |
*/5 * * * * | Every 5 minutes |
0 * * * * | Every hour |
0 */2 * * * | Every 2 hours |
0 0 * * * | Every day at midnight |
0 2 * * * | Every day at 2:00 AM |
0 9 * * 1-5 | Weekdays at 9:00 AM |
0 9 * * 1 | Every Monday at 9:00 AM |
0 0 1 * * | First day of every month |
30 18 * * 5 | Every Friday at 6:30 PM |
0 0 1 1 * | January 1st at midnight |
How to Read a Cron Expression
30 2 * * 1-5
│ │ │ │ │
│ │ │ │ └── 1-5 = Monday to Friday
│ │ │ └──── * = every month
│ │ └────── * = every day of month
│ └──────── 2 = 2 AM
└─────────── 30 = minute 30
Reading left to right: minute 30, hour 2, every day of month, every month, Monday through Friday. Put together: runs at 2:30 AM, Monday through Friday.
A slightly more involved example:
*/10 9-17 * * 1-5
This runs every 10 minutes during hours 9 through 17, Monday through Friday. Worth being precise about the last hour here: the hour field 9-17 includes the entire 17 o'clock hour — that is, 5:00 PM through 5:59 PM — not just the moment 5:00 PM itself. Combined with the */10 minute step, the job's actual last run of the day is 5:50 PM, not 5:00 PM. If you wanted the schedule to stop firing at 5:00 PM sharp, you'd need 9-16 instead of 9-17.
Cron Expression vs Cron Job
A cron expression is only the schedule:
0 2 * * *
A complete cron entry also needs the command to run:
0 2 * * * /usr/bin/php /var/www/app/backup.php
The first five fields define when it runs; everything after that is the command itself. A couple of things to know about that command portion: the path should be correct and, ideally, absolute (more on why below), and cron typically runs commands with a much more limited environment than your interactive shell — environment variables you rely on in a terminal session (like a customized PATH) may simply not be set when cron runs the same command.
How to Create a Cron Job on Linux
Step 1 — open your crontab:
crontab -e
This opens the current user's cron configuration — no root access needed for a job that only needs to run under your own user account.
Step 2 — add a line with your schedule and command:
0 2 * * * /usr/bin/php /var/www/app/backup.php
Step 3 — save and exit. The exact keys depend on which editor your system opens by default — commonly Nano or Vim — so follow that editor's own save instructions.
Step 4 — confirm it was saved:
crontab -l
This lists your current user's active cron jobs.
PHP Cron Job Example
A minimal PHP script that logs each time it runs:
<?php
file_put_contents(
__DIR__ . '/cron.log',
date('Y-m-d H:i:s') . " - Cron executed\n",
FILE_APPEND
);
And the cron entry to run it every five minutes:
*/5 * * * * /usr/bin/php /var/www/app/cron.php
A valid entry like this attempts to run the script every five minutes — whether it actually succeeds depends on several things worth checking:
- the PHP binary path is correct for that server (
which phpconfirms it) - the script path is absolute, not relative
- the script file has the permissions needed to be read and executed
- the script doesn't assume a particular working directory — cron doesn't run it from the directory you'd expect
- errors are logged somewhere you'll actually see them, especially while debugging
Cron Timezone Considerations
Cron uses whatever timezone the system (or, on managed platforms, the scheduler) is configured with — not your own local timezone as a developer. A schedule of 0 9 * * * runs at 9:00 AM server time, which may or may not match 9:00 AM where you are. Cloud hosting platforms commonly default to UTC. In regions that observe daylight saving time, a server's local time can also shift by an hour twice a year, which can move a schedule's effective time if the server isn't set to UTC. Always confirm the actual configured timezone on the system running the job, and test a new schedule against that timezone rather than assuming it matches yours.
Common Cron Mistakes
1. Wrong field order. The traditional five-field order is minute hour day-of-month month day-of-week — not hour-first, which is easy to assume by mistake.
2. Using 24 for midnight. The hour field runs 0–23; midnight is 0, not 24.
3. Forgetting absolute paths.
0 2 * * * php backup.php
can fail, because cron's environment and working directory differ from your interactive shell — the php command or the relative script path may simply not resolve. Prefer:
0 2 * * * /usr/bin/php /var/www/app/backup.php
4. Assuming the job ran successfully. A correctly written schedule only means cron attempted to run the command at the right time — not that the command succeeded.
5. Ignoring output and errors. Redirect output somewhere you'll actually check:
*/5 * * * * /usr/bin/php /var/www/app/cron.php >> /var/www/app/cron.log 2>&1
>> appends standard output to the log file, and 2>&1 sends standard error to that same place instead of letting it vanish. For a job that runs often over a long period, plan for log rotation too, or the file will keep growing indefinitely.
6. Scheduling overlapping jobs. If a job is scheduled every 5 minutes but sometimes takes 12 minutes to finish, multiple instances can end up running at once. Depending on what the job does, that can mean duplicate work, race conditions, or worse. Applications that risk this generally need some form of locking, a queue, or another mechanism to prevent the same job from running twice concurrently — worth knowing about, though a full solution is its own topic beyond a single cron line.
Cron Expression vs Human-Readable Schedule
0 2 * * * is compact, but it isn't self-explanatory to everyone at a glance — "every day at 2:00 AM" is the same schedule, spelled out. That gap between the compact syntax and a plain-English description is exactly where a generator that reads the expression back to you in plain language is genuinely useful, rather than just a convenience.
How to Use Kravoy's Cron Expression Generator
Kravoy's Cron Expression Generator helps you build and understand a schedule without memorizing the field order:
- Open the Cron Expression Generator.
- Set the minute, hour, day-of-month, month, and day-of-week fields (or start from one of the built-in presets, like "every weekday at 9 AM").
- The expression itself updates as you go.
- Read the plain-language description of what the schedule means.
- Check the next several run times, calculated from the current time.
- Copy the finished expression into your scheduler.
The tool helps you construct and understand a schedule — it doesn't execute anything itself; actually running the job still happens on your own server or scheduler.
Cron vs Other Scheduling Systems
| System | Typical use |
|---|---|
| Cron | Scheduled commands on Unix-like systems |
| Windows Task Scheduler | Scheduled tasks on Windows |
| Laravel Scheduler | Application-level scheduling inside a Laravel app |
| Queue worker | Processing jobs placed on a queue, not time-based scheduling itself |
| Cloud scheduler (managed) | Cloud-provider-managed scheduled triggers |
These systems don't all share the same syntax or behavior. A cron expression that works unchanged in plain Unix cron won't necessarily work unchanged in a different scheduler — always check the specific system's own documentation before assuming compatibility.
Cron Syntax Variations
This article focuses on traditional five-field Unix-style cron, which is by far the most common form you'll encounter. Worth knowing that other formats exist: some extended cron implementations add a seconds field (six fields total), Quartz (common in the Java ecosystem) uses its own distinct schedule syntax, and various cloud schedulers define their own conventions loosely inspired by cron. These aren't interchangeable with the five-field format covered here — if you're working with one of them, treat it as its own syntax rather than assuming five-field rules apply.
Practical Cron Debugging Checklist
- Is the field order correct — minute, hour, day-of-month, month, day-of-week?
- Is the command path absolute?
- Is the executable (PHP, Node, etc.) actually available at that path?
- Does the script have the permissions it needs?
- Is the server's timezone what you expect?
- Does the command work when you run it manually?
- Are errors being logged somewhere you'll see them?
- Is the cron service itself running on the server?
- Is the job running under the user account you expect?
- Could two executions overlap if the job runs long?
- Does your scheduler actually support the exact syntax you wrote?
Frequently Asked Questions
What is a cron expression?
A schedule made of five fields — minute, hour, day-of-month, month, day-of-week — that tells a scheduler when to run a command.
What does * * * * * mean?
Every field is a wildcard, so the job runs every minute of every hour of every day.
How do I run a cron job every 5 minutes?
*/5 * * * *
How do I run a cron job every day at midnight?
0 0 * * *
What is the difference between a cron job and a cron expression?
The expression is just the schedule. A cron job is the complete entry — the schedule plus the actual command to run.
Does cron use local time or server time?
Server time — specifically whatever timezone the system (or scheduler) is configured with, which may differ from your own local timezone.
How do I check my existing cron jobs?
crontab -l
Can I use cron to run a PHP script?
Yes — point the cron entry at your PHP binary and the script's absolute path, for example /usr/bin/php /var/www/app/cron.php.
Why is my cron job not running?
Common causes: a relative rather than absolute path, an incorrect binary path, missing file permissions, the wrong timezone assumption, or the cron service itself not running. Work through the debugging checklist above, starting with whether the exact command runs successfully when you type it manually.