Cron Syntax Cheat Sheet — Every Field Explained

Published 2026-05-25 · Updated 2026-06-01

Your deploy pipeline ran at 3 AM instead of 3 PM. Your backup job fires every minute instead of every hour. Cron syntax is five fields of pure ambiguity — here's how to read and write it without guessing.

This guide covers what every cron field means, the special characters that modify them, 15+ ready-to-use schedule expressions, platform-specific differences across Linux, GitHub Actions, AWS, and Kubernetes, and the most common reasons a cron job silently fails. Bookmark it, or use the interactive Cron Explainer to test expressions in real time.

Cron Field Reference

A standard cron expression consists of exactly five fields separated by spaces. Each field controls one dimension of the schedule. The fields are always read left to right in this order:

Field Position Allowed Values Special Characters Example
Minute 1st 0–59 * , - / */10 = every 10 minutes
Hour 2nd 0–23 * , - / 9-17 = 9 AM through 5 PM
Day of month 3rd 1–31 * , - / ? 1,15 = 1st and 15th
Month 4th 1–12 or JAN–DEC * , - / 1,4,7,10 = quarterly
Day of week 5th 0–6 (Sun=0) or SUN–SAT * , - / ? 1-5 = Monday through Friday

Special character reference

These characters can be combined. For example, 0-30/10 in the minute field matches minutes 0, 10, 20, and 30 — a step applied over a range.

Common Cron Schedules

Below are 15+ expressions covering the most frequently needed schedules. Copy them directly or paste them into the Cron Explainer to verify run times in your timezone.

ExpressionScheduleNotes
* * * * * Every minute Use with caution — high frequency can overload resources
*/5 * * * * Every 5 minutes Common for health checks and lightweight polling
0 * * * * Every hour (on the hour) Minute field is 0, not *
0 0 * * * Every day at midnight Midnight in the server's configured timezone
0 12 * * * Every day at noon
0 9 * * 1 Every Monday at 9 AM 1 = Monday in standard cron (0 = Sunday)
0 8 * * 1-5 Weekdays at 8 AM 1-5 covers Monday through Friday
0 0 1 * * First of every month at midnight
*/15 8-17 * * 1-5 Every 15 min during business hours 8:00 AM through 5:45 PM, weekdays only
0 9,17 * * * Twice a day (9 AM and 5 PM) Comma separates the two hours
0 2 * * 0 Every Sunday at 2 AM Common slot for weekly maintenance
30 2 * * * Daily at 2:30 AM Popular for backups — avoids the midnight spike
0 */6 * * * Every 6 hours Runs at 0:00, 6:00, 12:00, 18:00
0 0 1 1,4,7,10 * Quarterly (Jan, Apr, Jul, Oct 1st) Midnight on the first day of each quarter
0 9 * * 1-5 Weekdays at 9 AM Typical for business-hours notifications

Schedules cron cannot express directly

Every 30 seconds. Standard cron's minimum granularity is one minute. The usual workaround is two cron entries: one running the command at the top of the minute, and a second that sleeps 30 seconds before running it. For example, in a crontab you would write two lines, both set to * * * * *: the first runs the command directly, and the second runs sleep 30 && /path/to/command. Some platforms like AWS EventBridge support a seconds field natively, making this unnecessary.

Last day of the month. There is no "L" modifier in standard cron. Months have 28, 29, 30, or 31 days, so no single day-of-month value works universally. The common workaround is a daily job that checks whether tomorrow is the 1st: 0 0 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /path/to/command. Some extended implementations (Quartz, Spring) support L in the day-of-month field.

Every other Wednesday. Cron has no concept of "every Nth occurrence" of a weekday within a month. You can schedule every Wednesday (0 0 * * 3) and add logic inside the script to check the week number and skip even or odd weeks. Alternatively, use an external scheduler that supports richer recurrence rules.

Why My Cron Didn't Run — Troubleshooting

Cron jobs fail silently more often than they fail loudly. Here are the five most common causes, each of which has tripped up experienced engineers.

Timezone mismatch

The cron daemon runs in the server's system timezone unless configured otherwise. If your server is set to UTC but you wrote the expression thinking in US Eastern time, a job scheduled for 0 9 * * * runs at 9:00 UTC — which is 4:00 or 5:00 AM Eastern depending on daylight saving time. Always check the active timezone with timedatectl or date +%Z on the host. Cloud platforms like GitHub Actions and AWS EventBridge run exclusively in UTC, so convert before writing the expression. For more on timezone conversions, see the Unix Timestamp Converter.

Daylight Saving Time transitions

When clocks spring forward, the skipped hour does not exist. A job scheduled for 2:30 AM in a US timezone will not run on the night DST begins, because 2:30 AM never occurs. Conversely, when clocks fall back, the repeated hour may cause the job to run twice. If your job is time-sensitive, schedule it outside the 1:00 AM–3:00 AM window or pin the server to UTC.

Day-of-week vs. day-of-month (OR logic)

In classic Vixie cron (the implementation on most Linux distributions), when both day-of-month and day-of-week are set to non-wildcard values, the job runs if either condition is true — not both. This is a documented behavior but widely misunderstood. If you write 0 9 15 * 1 intending "the 15th, but only if it's a Monday," the job actually runs every Monday and every 15th. To enforce both conditions, set one field to * and add a conditional check inside the script.

Five-field vs. six-field confusion

Standard cron uses five fields (minute through day-of-week). Some systems — notably Quartz Scheduler, Spring, and AWS EventBridge — prepend a seconds field, making it six fields. If you paste a five-field expression into a six-field system, every field shifts right by one position, producing a wildly different schedule. If you paste a six-field expression into a five-field system, cron rejects it or misparses it. Always verify which format your platform expects.

PATH and environment issues in crontab

Cron does not source your shell profile. The default PATH in a crontab is typically limited to /usr/bin:/bin, so commands that work in your terminal may fail under cron because their binary is not on the path. Fix this by using absolute paths to executables (e.g., /usr/local/bin/node instead of node) or by setting PATH at the top of your crontab file. The same applies to environment variables: if your script depends on DATABASE_URL or similar, export it in the crontab or in a wrapper script. For complex configurations stored in JSON, a JSON formatter helps verify the config file is valid before the job reads it.

Platform-Specific Gotchas

Cron syntax is nearly universal, but the runtime environment varies significantly across platforms. The table below summarizes the key differences you need to know before deploying a schedule.

Platform Timezone Seconds Field Special Syntax Gotcha
Linux crontab System TZ No Standard 5-field PATH is not inherited from your shell; set it explicitly
GitHub Actions UTC only No Standard 5-field Uses on.schedule in YAML; shortest practical interval is ~5 min due to queue delays
Kubernetes CronJob UTC default; configurable from v1.27+ via timeZone field No Standard 5-field Missed schedule policy (concurrencyPolicy, startingDeadlineSeconds) must be set or jobs silently drop
AWS EventBridge UTC Yes (6-field) ? required in either day-of-month or day-of-week Also supports rate() expressions as an alternative to cron
Vercel Cron UTC No Standard 5-field Hobby plan limited to daily; shorter intervals require Pro plan
Cloudflare Workers UTC No Standard 5-field Configured in wrangler.toml under [triggers]; max 3 triggers per worker on free plan

When moving a cron expression between platforms, always check three things: whether the platform uses five or six fields, whether it runs in UTC or a configurable timezone, and whether it supports the ? character. Getting any one of these wrong produces a schedule that looks correct but fires at the wrong time.

Reading a Cron Expression Step by Step

To demystify the process, here is how to read an expression from scratch. Take */15 8-17 * * 1-5 and work through it field by field:

  1. Minute: */15 — starting at minute 0, every 15 minutes. That means :00, :15, :30, :45.
  2. Hour: 8-17 — during hours 8 through 17 (8:00 AM through 5:45 PM, since minute 45 of hour 17 is still matched).
  3. Day of month: * — every day of the month.
  4. Month: * — every month.
  5. Day of week: 1-5 — Monday through Friday.

Combined: every 15 minutes during business hours on weekdays. This expression produces 40 runs per day (4 per hour across 10 hours) and 200 per work week. Reading each field in isolation, then combining them, is the most reliable way to decode any cron expression. The Cron Explainer tool automates this and shows you the exact next run times.

Writing Better Cron Expressions

Beyond syntax correctness, a few practices reduce the chance of schedule-related incidents:

Cron vs. Other Scheduling Approaches

Cron is the right tool for recurring, time-based schedules on a single host or within a platform that accepts cron syntax. It is not the right tool for event-driven workflows (use a message queue), distributed task scheduling across many nodes (use a dedicated scheduler like Celery Beat or Temporal), or sub-second intervals (use a timer in your application code). Understanding where cron fits prevents over-engineering simple schedules and under-engineering complex ones.


For a full set of browser-based utilities, visit the Developer Tools hub.

Related tools

Joe — Software engineer with 20+ years of experience. Built ToolRack to provide fast, private tools without the bloat.