Cron Expression Builder & Tester
Build a cron expression with five simple inputs, preview the next five fire times, and copy the result. Twelve curated presets for the schedules you actually need — hourly, daily, weekday, monthly, yearly.
Cron expression
0 9 * * *
at 9:00
Next 5 fire times (local)
- Sun, May 17, 2026, 09:00 AM
- Mon, May 18, 2026, 09:00 AM
- Tue, May 19, 2026, 09:00 AM
- Wed, May 20, 2026, 09:00 AM
- Thu, May 21, 2026, 09:00 AM
Wildcards cheatsheet
- * — every value
- 5 — exactly 5
- 1-5 — 1 through 5
- 1,3,5 — list
- */15 — every 15
Cron, demystified
Cron expressions look intimidating because they pack five different scheduling concepts into five whitespace-separated fields with no labels. Once you internalize the order — minute, hour, day-of-month, month, day-of-week — they become legible at a glance. The cheatsheet: * means "every value", 5 means "exactly 5", 1-5 means "1 through 5 inclusive", 1,3,5 is a list, and */15 is "every 15 starting from 0".
The minute field is where most production cron jobs go wrong. People write * * * * * for "hourly" and wonder why their database is on fire — that's every minute. The fix is to anchor to 0: 0 * * * * means "at minute zero of every hour" — that is, hourly.
The day-of-week field is the other landmine. POSIX cron treats day-of-month and day-of-week as an OR condition when both are specified. So 0 0 15 * MON fires on the 15th of every month and every Monday — not "the 15th if it's a Monday". If you need that, do the filtering inside the job, not in the cron line.
Timezones are the silent killer. By default, cron runs in the server's local time — which is almost always UTC in cloud environments. A line that reads 0 9 * * * fires at 9 AM UTC, which is 4 AM Eastern in winter and 5 AM Eastern in summer. Either set the TZ environment variable explicitly in your crontab (or DAG, or Kubernetes manifest), or do the math and write your expression in UTC. We've audited dozens of incident postmortems where the root cause was "the daily report ran 5 hours later than the team thought."
Step values are subtler than they look. */15 * * * * means "every 15 minutes starting at minute 0" — so :00, :15, :30, :45. But 5/15 * * * * means "starting at minute 5, every 15 minutes" — :05, :20, :35, :50. Useful if you have multiple servers and want to stagger their cron jobs to avoid the thundering-herd problem at exact zero.
Year field exists in some implementations but not POSIX. AWS EventBridge accepts a sixth field (year). Quartz, used by Java schedulers, accepts seconds (so a 6-field expression in Quartz is second minute hour day month dow). Kubernetes CronJob, GitHub Actions schedule, GitLab CI schedule, and standard Unix cron all use the 5-field POSIX format that this builder generates.
When NOT to use cron. Cron is a time-based trigger — it has no idea whether your previous run finished, whether the queue is backed up, or whether your dependencies are healthy. For anything that absolutely cannot run twice in parallel, or cannot run if the previous run failed, you want a queue worker with distributed locking — not cron. A common pattern: cron fires every 5 minutes, the job acquires a Redis lock, and skips if another instance is already running. This is also why we usually deploy API-driven background workers instead of crontab for production SaaS.
Need help architecting a scheduled job system that won't bite you at 3 AM? See our services overview or book a 20-minute architecture call.
FAQs
Why does my cron expression seem to fire one hour off?
Almost always a timezone mismatch. Cron daemons run in the server's local time by default — which is usually UTC in cloud environments. So 0 9 * * * means 9 AM UTC, not 9 AM in your office. Either explicitly set TZ in the crontab, or do the offset math in your expression (4 AM ET in summer becomes 8 AM UTC).
What is the difference between '0 0 * * 0' and '0 0 * * 7'?
Both mean Sunday in most cron implementations — 0 and 7 are both Sunday in Vixie cron and its descendants. We use 0-6 (Sunday-Saturday) in this builder for consistency. If you're targeting AWS CloudWatch Events or Quartz, note that they use 1-7 (Sunday-Saturday) — slightly different from POSIX.
Can I use this for AWS Lambda or Kubernetes CronJobs?
Mostly yes — the 5-field standard cron format works in Kubernetes CronJobs, GitLab CI, and most Unix cron flavors. AWS EventBridge uses a 6-field variant (it adds a year field and uses ? instead of * for day-of-month/day-of-week conflict). Use the expression we generate, then adapt for the platform-specific quirks.
What happens when day-of-month and day-of-week are both specified?
POSIX cron treats it as an OR condition: the job fires when either matches. So '0 0 15 * MON' runs on the 15th of the month AND every Monday. This is counterintuitive — most people read it as AND. If you need 'the 15th if it's a Monday', do the filtering inside your job, not in the cron expression.
What's the smallest cron interval I should use?
Standard cron runs at minute granularity — '* * * * *' is the fastest. For sub-minute scheduling, use a queue worker or a long-running daemon. Hitting cron every minute for jobs that take 30 seconds is a smell — it causes overlap, missed fires when the host is busy, and noisy logs. Switch to an event-driven model.
Related tools
Related engineering reading
All postsBuilding Multi-Tenant SaaS on Postgres RLS
Row-level security patterns for isolating tenant data without separate databases.
Read postInternal Tools Platform Engineering Guide
Architectural patterns for ops dashboards, admin panels, and back-office UIs.
Read postNext.js + Stripe: The Complete Integration Guide
Server Actions, the Payment Element, webhook idempotency, and subscriptions.
Read post
Cron jobs eating your 3 AM?
We design scheduled-job systems that don't silently double-run, don't fail without alerts, and don't depend on a single crontab line nobody remembers writing. Talk to us about queue-driven workers, idempotency design, or just fixing the cron lines you have.
Or reach us directly: (770) 652-1282 · beltz@quantlabusa.dev