⏰ Cron Expression Builder & Explainer
Build a schedule visually or paste an existing cron expression to get a plain-English explanation and next 5 run times.
Cron Expressions Demystified: What That String of Stars and Numbers Actually Means
If you have ever peeked at a Linux server, a CI/CD pipeline, or a cloud function configuration, you have almost certainly seen something like 0 2 * * * sitting in a schedule field. It looks like someone's cat walked across the keyboard. But once you understand what each piece means, cron expressions become one of the most satisfying little languages in all of computing — five tiny fields that can describe almost any repeating schedule imaginable.
Where Did Cron Come From?
Cron is a job scheduler that has lived inside Unix and Linux systems since the 1970s. The name comes from the Greek word chronos, meaning time. It runs silently in the background, waking up every single minute, checking a table of scheduled tasks (the "crontab"), and running anything whose schedule matches the current time. For fifty years, this same basic mechanism has been backing up databases, sending emails, clearing caches, and doing a million other jobs that humans would rather not do by hand every day.
Today you find cron syntax everywhere: GitHub Actions uses it to schedule automated workflows, AWS Lambda and Google Cloud Scheduler accept it for serverless triggers, Kubernetes uses CronJob objects, and pretty much every CI/CD platform on the planet has borrowed the format. Learning to read and write cron expressions is one of those quietly powerful skills that pays off again and again.
The Five Fields — One at a Time
A standard cron expression has exactly five fields, separated by spaces, in this order:
minute hour day-of-month month day-of-week
Think of them as increasingly broad time circles, from the smallest (which minute of an hour?) to the largest (which day of the week?). Let's walk through each one.
Field 1 — Minute (0–59). This is which minute of the hour you want the job to run. A 0 means the very top of the hour, 30 means half past, and * means every single minute.
Field 2 — Hour (0–23). This is which hour of the day, using 24-hour time. Midnight is 0, noon is 12, and 11 PM is 23. An asterisk means every hour.
Field 3 — Day of Month (1–31). Which day of the month. 1 means the first, 15 the fifteenth. Useful for payroll runs or monthly reports.
Field 4 — Month (1–12). January is 1, December is 12. Want something to run only in summer? Use 6,7,8.
Field 5 — Day of Week (0–6). Sunday is 0, Monday is 1, all the way to Saturday at 6. Some systems also accept 7 as Sunday — and CI systems sometimes let you write sun, mon, etc.
The Special Characters That Make It Powerful
The real expressiveness comes from a small set of special characters you can use inside any field:
Asterisk * — Means "every possible value." * in the minute field means every minute. * in the month field means every month. This is the most common character in any cron expression.
Slash / (step values) — The / character means "every N." So */15 in the minute field means "every 15 minutes." The * part says "start from the beginning," and /15 says "step by 15." You could also write 0/15 to be explicit that you start at zero — same result.
Comma , (lists) — Lets you specify multiple individual values. 0,30 in the minute field means "at minute 0 and also at minute 30," giving you a task that fires twice per hour. 1,3,5 in the day-of-week field means Monday, Wednesday, Friday.
Hyphen - (ranges) — Specifies a range of values. 1-5 in the day-of-week field means Monday through Friday. 9-17 in the hour field means every hour from 9 AM to 5 PM. You can even combine ranges with steps: 0-30/10 means at minutes 0, 10, 20, and 30.
Reading Real Examples
Let's decode a few expressions you will actually encounter in the wild:
*/5 * * * * — The minute field says "every 5 minutes," everything else is asterisks meaning "any." Result: runs every 5 minutes, 24 hours a day, every day. Classic for health checks or polling tasks.
0 2 * * * — Minute 0, hour 2, everything else wildcard. Runs once a day at 2:00 AM. The standard slot for nightly database backups — chosen because almost nobody is using the app at 2 AM.
0 9 * * 1-5 — Minute 0, hour 9, any day of month, any month, weekdays only (1–5 = Mon–Fri). This runs at 9:00 AM every weekday. Perfect for sending a morning report email.
30 6 1 * * — 6:30 AM on the 1st of every month. Monthly billing runs, month-start reports, subscription renewals — this pattern is everywhere.
0 0 1 1 * — Midnight on January 1st. A yearly task. Useful for archiving old data at the start of a new year or rotating API keys annually.
CI-Style Shortcuts: The @ Aliases
Modern cron implementations — and CI platforms like GitHub Actions — support convenient shortcuts for the most common patterns:
@hourly→ runs at the start of every hour (same as0 * * * *)@daily→ runs once a day at midnight (same as0 0 * * *)@weekly→ runs every Sunday at midnight (same as0 0 * * 0)@monthly→ runs on the 1st of each month at midnight (same as0 0 1 * *)@yearlyor@annually→ runs on January 1st at midnight (same as0 0 1 1 *)
These are not valid in the original Unix cron but are supported in most modern schedulers. They make intent immediately obvious without needing to decode field positions.
The Tricky Part: Day-of-Month vs Day-of-Week
One genuine source of confusion is what happens when you set both the day-of-month field and the day-of-week field to something other than *. Most cron implementations use an OR rule: the job runs if either condition matches. So 0 0 15 * 5 would run at midnight on the 15th of every month AND also on every Friday. This surprises people who expect an AND relationship. The safe approach: only ever restrict one of the two day fields at a time, and leave the other as *.
Common Mistakes and How to Avoid Them
The most frequent error is off-by-one on hours — forgetting that hours run 0–23, not 1–24. Writing 24 in the hour field usually causes an error or gets silently ignored. Similarly, months run 1–12 (not 0–11 like JavaScript's Date months), and days of the week start at 0 for Sunday, not 1.
Another trap: cron runs in the server's timezone, not yours. A job scheduled for 0 9 * * * on a UTC server runs at 9 AM UTC — which might be 2:30 PM in India or 5 AM in New York. Always be explicit about which timezone your scheduler uses, and consider using UTC internally to avoid daylight-saving time surprises.
Finally, don't schedule many jobs at exactly 0 * * * * or 0 0 * * * if your system has dozens of tasks. The "thundering herd" effect — everything starting simultaneously — can spike CPU and database load. Stagger them: put one job at 0 0, another at 5 0, another at 10 0.
The builder above removes the guesswork entirely. Pick your schedule visually, see the expression update instantly, and verify the next five run times are exactly what you intended — no server surprises required.