Cron Expression Syntax Explained: A Practical Cheat Sheet
Learn how to read and write cron expressions with real examples — every 5 minutes, daily at midnight, weekdays only — plus the gotchas that trip up even senior developers.
Cron expressions are one of those things every developer half-remembers. You know it's five fields, you know * means "every", and then you end up googling "cron every 5 minutes" for the tenth time anyway.
This is the cheat sheet we wish existed: the syntax, the most common expressions ready to copy-paste, and the gotchas that cause jobs to fire at the wrong time (or not at all).
The anatomy of a cron expression
A standard cron expression has five fields, separated by spaces, read from left to right:
┌───────────── minute (0–59)
│ ┌───────────── hour (0–23)
│ │ ┌───────────── day of month (1–31)
│ │ │ ┌───────────── month (1–12)
│ │ │ │ ┌───────────── day of week (0–6, Sunday = 0)
│ │ │ │ │
* * * * *
Each field accepts a few operators:
*— every value ("every minute", "every hour"…),— a list of values (1,15= the 1st and the 15th)-— a range (1-5= 1 through 5)/— a step (*/5in the minute field = every 5 minutes)
That's 95% of the syntax. Combine them and you can express almost any schedule.
Common cron expressions (copy-paste ready)
Every minute:
* * * * *
Every 5 minutes:
*/5 * * * *
Every hour, on the hour:
0 * * * *
Every day at midnight (a classic for backups):
0 0 * * *
Every day at 6:30 AM:
30 6 * * *
Every Monday at 9 AM (weekly reports):
0 9 * * 1
Weekdays only, at 8 AM:
0 8 * * 1-5
First day of every month at midnight (billing, invoicing):
0 0 1 * *
Every 15 minutes during business hours, weekdays:
*/15 9-17 * * 1-5
Twice a day, at 6 AM and 6 PM:
0 6,18 * * *
The gotchas that bite people
1. Day-of-month and day-of-week are OR, not AND
This is the most infamous cron quirk. Take this expression:
0 0 13 * 5
You might read it as "midnight on Friday the 13th". In standard cron it actually fires on the 13th of every month AND every Friday — the two day fields are combined with OR when both are restricted. If you need a true "Friday the 13th" job, check the weekday inside your script instead.
2. Cron runs in the server's timezone
0 9 * * * means 9 AM somewhere — and that somewhere is wherever your server thinks it is, which for most cloud VMs is UTC. Your "9 AM report" lands in inboxes at 4 AM in New York or at noon in Istanbul.
Worse, if your server's timezone observes daylight saving time, a job scheduled at 2:30 AM may run twice one night in autumn and not at all one night in spring.
The fix: schedule in UTC when you can, or use a scheduler that supports per-job timezones. CronSpark lets you attach an explicit timezone (like Europe/Istanbul or America/New_York) to every job, so "9 AM" means 9 AM for your users — DST handled for you.
3. */30 in the hour field doesn't mean "every 30 hours"
Steps operate within a field's range. */30 in the hour field (0–23) only matches hour 0 — so the job runs once a day at midnight, not every 30 hours. Cron simply can't express intervals that don't fit inside a single field. If you need "every 36 hours" or "every 10 seconds", you want an interval-based scheduler, not a cron expression.
4. A schedule is not a guarantee
The expression only says when the job should fire. If the server was rebooting at that moment, the cron daemon was misconfigured, or the script crashed halfway — cron won't tell you. The expression was "correct" and the job still didn't run.
That's why pairing schedules with monitoring matters: an external service that expects each run and alerts you when one goes missing. We wrote about that pattern in what is a dead man's switch monitor.
Don't want to memorize any of this?
Fair. Two shortcuts:
- Read expressions with a translator — tools like cronstrue turn
*/15 9-17 * * 1-5into plain English. - Build them visually — CronSpark has a visual cron builder that shows a live human-readable preview and the next five run times before you save a job, so you never deploy a schedule that fires at the wrong hour.
Summary
Five fields — minute, hour, day of month, month, day of week — plus four operators (*, ,, -, /) cover nearly every schedule you'll need. Watch for the OR behavior of the two day fields, be explicit about timezones, and remember that a cron expression only requests a run. To know your jobs actually ran, put a monitor like CronSpark behind them.