⚙️ Cron Expression Builder
Build, decode, and preview cron schedule expressions. Edit any field or type directly.
What Cron Expressions Actually Mean — And Why Getting Them Right Matters
Every developer has been there: a scheduled job that was supposed to run at 9 AM every weekday silently fires at midnight, or worse, runs every single minute because someone wrote * * * * * when they meant 0 0 * * *. Cron expression errors are insidious. They don't throw exceptions. They don't fail loudly. They either run too often, not often enough, or never at all — and you only notice when the nightly report is missing or the server has been hammering the database every 60 seconds for three days.
The cron scheduling system has been around since Version 7 Unix in 1979, and its five-field notation has barely changed. That longevity is a testament to its elegance, but also its terseness. A string like 0 9 * * 1-5 is perfectly readable once you know what you're looking at, but opaque to anyone who hasn't memorized the field order.
The Five Fields, Explained Without Hand-Waving
A standard cron expression has exactly five space-separated fields, read left to right: minute (0–59), hour (0–23), day of month (1–31), month (1–12), and day of week (0–6, where 0 is Sunday). The mental model that makes these stick is: "When during the hour? Which hour? Which day of the month? Which month? Which day of the week?"
Each field accepts four kinds of values. A bare number (9) means exactly that value. An asterisk (*) means every valid value. A hyphenated range (1-5) means every value from the first to the second, inclusive. A step expression (*/15 or 0-30/10) means every Nth value — either across the full range or within a specified sub-range. And comma-separated values (1,15,28) let you specify an explicit list.
These can be combined: 0,30 8-18 * * 1-5 means "at minute 0 and minute 30, during hours 8 through 18, every day of the month, every month, on weekdays only" — in plain English, twice per hour during business hours on working days.
The Day-of-Month vs Day-of-Week Trap
The interaction between the fourth and fifth fields trips up experienced engineers. When both day-of-month and day-of-week are set to something other than *, most cron implementations (including Vixie cron, which is what Linux uses) treat them as a union rather than an intersection. 0 9 1 * 1 does NOT mean "9am on the 1st of the month only if it's a Monday" — it means "9am on the 1st of the month OR any Monday." If you wanted the intersection, you need to handle that in your script logic, not in the cron expression itself.
This is one of the most quietly broken assumptions in scheduled task management. A team sets up a report to run on the 15th on weekdays, then notices it's running on random Mondays and Wednesdays throughout the month. The fix is straightforward once you know the rule: use only one day-dimension at a time in the cron expression and use the other in your script's guard clause if needed.
Step Values and Their Practical Uses
The slash syntax is what makes cron expressions genuinely powerful for periodic scheduling. */5 in the minute field means "every 5 minutes," which is far cleaner than listing 0,5,10,15,20,25,30,35,40,45,50,55. But the more nuanced form, start-end/step, is underused. 0-30/10 * * * * runs at minutes 0, 10, 20, and 30 — then stops. It does not run at 40 or 50. This is useful for jobs that need to run only in the first half of the hour, or for rate-limiting a polling task during a specific window.
For hour-level granularity: 0 */4 * * * runs at 00:00, 04:00, 08:00, 12:00, 16:00, and 20:00 every day. Note that it always starts from hour 0, not from when the daemon started. This "anchored to epoch" behavior is important: */4 will always give you those specific hours, not "every 4 hours from some arbitrary start time."
Common Real-World Patterns
Several cron patterns appear so frequently they're worth memorising. 0 0 * * * is the classic daily midnight run — used for log rotation, nightly backups, and daily report generation. 0 0 1 * * starts monthly jobs on the first of the month, perfect for billing cycles and monthly summaries. 0 0 * * 0 runs weekly on Sunday midnight, common for heavier maintenance tasks. */5 * * * * is the go-to for lightweight polling — checking a queue, syncing a feed, or pinging an external service. And 0 9-17 * * 1-5 runs hourly during business hours on weekdays, useful for jobs that only make sense when staff are present.
For deployment pipelines and CI systems, 0 2 * * 1-5 — 2 AM on weekdays — is popular because it gives engineers something to wake up to if it fails, rather than a weekend incident nobody notices until Monday.
Environment Differences to Watch For
Not all cron implementations are identical. Quartz Scheduler (common in Java applications) uses a six-field format with seconds as the first field and optionally a seventh field for year. AWS EventBridge also uses a six-field format but with years. If you're building expressions for Kubernetes CronJobs or GitHub Actions scheduled workflows, you're back to standard five-field Vixie cron syntax. Always verify which implementation your platform uses — the visual preview of upcoming runs is your best sanity check, because the same string can mean different things in different systems.
Timezone is another silent failure mode. Most cron daemons run in the system's local timezone, which means a server configured in UTC will fire your 0 9 * * * at 9 AM UTC, not 9 AM in your users' timezone. Cloud schedulers like AWS EventBridge let you specify a timezone explicitly. For self-hosted cron, prepend CRON_TZ=America/New_York (on systemd timers or GNU cron) or handle the offset yourself.
Testing Before You Deploy
The single most important habit when working with cron expressions is previewing the next several run times before deploying. An expression that looks reasonable can still be subtly wrong — 0 0 30 2 * will never fire because February never has a 30th day. 0 0 31 * * silently skips April, June, September, and November. These are exactly the kinds of mistakes that slip past code review because the expression parses without error.
Generating the next 10 or 20 scheduled times takes the guesswork out entirely. If the list shows runs happening at unexpected intervals, or shows no runs at all for months, you catch the problem before it becomes a production incident. Visual builders that show both the plain-English description and the concrete upcoming timestamps serve as a double check: the description tells you what you intended, and the timestamps tell you what the system will actually do.
Cron expressions are deceptively small. Five fields, a handful of operators, and you can describe almost any repeating schedule imaginable. The craft is in knowing the edge cases well enough that your 3-line string does exactly what you expect — no more, no less — every single time the scheduler fires.