Cron expressions are the backbone of scheduled tasks in Unix, Linux, macOS, CI/CD pipelines, cloud functions, and container orchestration. They look cryptic at first — 0 */6 * * 1-5 — but once you understand the five (or six) fields, you can schedule anything.
This cheat sheet covers the standard 5-field cron syntax, extended 6-field syntax (with seconds), every special character, and dozens of real-world examples you can copy-paste into your crontab, GitHub Actions, or Kubernetes CronJob.
Cron Syntax: The 5 Fields
A standard cron expression has five fields separated by spaces:
┌───────────── minute (0–59)
│ ┌───────────── hour (0–23)
│ │ ┌───────────── day of month (1–31)
│ │ │ ┌───────────── month (1–12 or JAN–DEC)
│ │ │ │ ┌───────────── day of week (0–7 or SUN–SAT, 0 and 7 = Sunday)
│ │ │ │ │
* * * * * Each field can contain a single value, a range, a list, a step, or a wildcard. The expression fires when all five fields match the current time.
Special Characters Explained
| Character | Meaning | Example |
|---|---|---|
* | Any value | * * * * * — every minute |
, | List separator | 0 8,12,18 * * * — at 8am, noon, 6pm |
- | Range | 0 9-17 * * * — every hour from 9am to 5pm |
/ | Step | */15 * * * * — every 15 minutes |
L | Last (non-standard) | 0 0 L * * — last day of month |
W | Nearest weekday (non-standard) | 0 0 15W * * — nearest weekday to 15th |
# | Nth weekday (non-standard) | 0 0 * * 5#3 — third Friday of month |
? | No specific value (Quartz) | 0 0 * * ? — any day of week |
Note: L, W, #, and ? are extensions used in Quartz (Java), Spring, and some cloud platforms. Standard Unix crontab only supports *, ,, -, and /.
Common Cron Patterns
Here are the patterns you'll use most often, ready to copy-paste.
Every X Minutes
* * * * * # Every minute
*/5 * * * * # Every 5 minutes
*/15 * * * * # Every 15 minutes
*/30 * * * * # Every 30 minutes
0 * * * * # Every hour (at minute 0) Daily Schedules
0 0 * * * # Midnight daily
0 6 * * * # 6:00 AM daily
30 8 * * * # 8:30 AM daily
0 12 * * * # Noon daily
0 23 * * * # 11:00 PM daily
0 0,12 * * * # Midnight and noon Weekly Schedules
0 0 * * 0 # Midnight every Sunday
0 9 * * 1 # 9 AM every Monday
0 9 * * 1-5 # 9 AM every weekday (Mon–Fri)
0 18 * * 5 # 6 PM every Friday
0 10 * * 6,0 # 10 AM every Saturday and Sunday Monthly and Yearly Schedules
0 0 1 * * # Midnight on the 1st of every month
0 9 15 * * # 9 AM on the 15th of every month
0 0 1 1 * # Midnight on January 1st (yearly)
0 0 1 */3 * # Midnight on the 1st, every 3 months (quarterly)
0 0 1 1,4,7,10 * # Midnight on the 1st of each quarter Business Hours
*/10 9-17 * * 1-5 # Every 10 min during business hours (Mon–Fri 9am–5pm)
0 9-17 * * 1-5 # Every hour during business hours
0 9,13 * * 1-5 # 9 AM and 1 PM on weekdays
30 8 * * 1-5 # 8:30 AM on weekdays (daily standup time) Extended 6-Field Syntax (Seconds)
Some systems (Quartz, Spring, AWS EventBridge) support a sixth field for seconds:
┌───────────── second (0–59)
│ ┌───────────── minute (0–59)
│ │ ┌───────────── hour (0–23)
│ │ │ ┌───────────── day of month (1–31)
│ │ │ │ ┌───────────── month (1–12)
│ │ │ │ │ ┌───────────── day of week (0–7)
│ │ │ │ │ │
* * * * * * */30 * * * * * # Every 30 seconds
0 */5 * * * * # Every 5 minutes (at second 0)
0 0 * * * * # Every hour (at second 0, minute 0) Warning: Standard Unix crontab does NOT support seconds. If you need sub-minute scheduling on Linux, use a workaround like running a script every minute that internally sleeps.
Cron in Different Environments
Linux / macOS Crontab
Edit your crontab with crontab -e:
# Backup database every night at 2 AM
0 2 * * * /usr/local/bin/backup-db.sh >> /var/log/backup.log 2>&1
# Clean temp files every Sunday at 3 AM
0 3 * * 0 find /tmp -mtime +7 -delete
# Health check every 5 minutes
*/5 * * * * curl -fsS https://hc-ping.com/your-uuid > /dev/null Key crontab tips:
- Always redirect output (
> /dev/null 2>&1) or cron will email you on every run. - Use full paths for commands — cron's
PATHis minimal. - Set
MAILTO=""at the top to disable email notifications entirely. - Use
crontab -lto list current jobs,crontab -rto remove all.
GitHub Actions
on:
schedule:
- cron: '0 6 * * 1-5' # 6 AM UTC, weekdays
- cron: '0 0 1 * *' # Midnight UTC, 1st of month GitHub Actions uses UTC only. Runs may be delayed by up to 15 minutes during peak load. Minimum interval is 5 minutes, but GitHub may throttle more frequent schedules.
Kubernetes CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-report
spec:
schedule: "0 8 * * *" # 8 AM daily
concurrencyPolicy: Forbid # Don't overlap runs
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
containers:
- name: report
image: myapp/report:latest
command: ["python", "generate_report.py"]
restartPolicy: OnFailure AWS CloudWatch / EventBridge
AWS uses a slightly different syntax with 6 fields (year is optional):
cron(0 18 ? * MON-FRI *) # 6 PM UTC, weekdays
cron(0 12 1 * ? *) # Noon UTC on the 1st of each month
rate(5 minutes) # Alternative: every 5 minutes (simpler)
Note that AWS uses ? for "no specific value" in either day-of-month or day-of-week (you must use ? in exactly one of them).
Debugging Cron Expressions
The most common cron bugs:
- Timezone confusion. Crontab runs in the system's local timezone. GitHub Actions and AWS use UTC. Always document which timezone your cron uses.
- Day-of-month AND day-of-week. In standard cron, if both are set (not
*), the job runs when either matches — not both. This catches people off guard.0 0 15 * 5runs on the 15th AND every Friday. - February 30th.
0 0 30 2 *will never fire. Cron silently skips impossible dates. - Step misunderstanding.
*/7 * * * *does NOT run every 7 minutes starting from the last run. It runs at minutes 0, 7, 14, 21, 28, 35, 42, 49, 56. The step divides the range, not the interval from last execution. - Overlapping runs. If a job takes 10 minutes but runs every 5, you'll get overlapping executions. Use a lock file or
concurrencyPolicy: Forbidin Kubernetes.
Advanced Patterns
First and Last Day of Month
Standard cron doesn't have "last day of month" — but you can script around it:
# Run on the last day of every month (Linux)
0 0 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /path/to/script.sh
In Quartz/Spring, use the L modifier: 0 0 0 L * ?
Every Other Week
Cron can't express "every other week" natively. Workaround: run weekly and check the week number inside your script:
# Every other Monday (even weeks)
0 9 * * 1 [ $(($(date +\%V) \% 2)) -eq 0 ] && /path/to/script.sh Random Delay (Jitter)
To avoid thundering-herd problems when many servers run the same cron:
# Sleep 0-300 seconds before running
*/5 * * * * sleep $((RANDOM \% 300)) && /path/to/health-check.sh Cron vs. Alternatives
| Tool | Best for | Limitations |
|---|---|---|
| crontab | Simple server-side scheduling | No retry, no dependency chain, no seconds |
| systemd timers | Modern Linux, with logging and dependencies | Linux only, more verbose config |
| Celery Beat | Python app scheduling with workers | Requires message broker (Redis/RabbitMQ) |
| Kubernetes CronJob | Containerized workloads | 1-minute minimum, cold start latency |
| AWS EventBridge | Serverless scheduling (Lambda, Step Functions) | AWS-specific syntax quirks |
| node-cron | In-process Node.js scheduling | Dies with the process, no persistence |
Build and Test Your Cron Expressions
The fastest way to get a cron expression right is to build it visually. Try DevToolkit's Cron Expression Builder — select your schedule with dropdowns, see the next 5 execution times instantly, and copy the expression. No guessing, no syntax errors.
It supports both standard 5-field and extended 6-field syntax, with human-readable descriptions of what the expression does. Perfect for validating expressions before deploying to production.
Quick Reference Card
| Schedule | Expression |
|---|---|
| Every minute | * * * * * |
| Every 5 minutes | */5 * * * * |
| Every hour | 0 * * * * |
| Every day at midnight | 0 0 * * * |
| Every weekday at 9 AM | 0 9 * * 1-5 |
| Every Monday at 9 AM | 0 9 * * 1 |
| 1st of every month | 0 0 1 * * |
| Every quarter | 0 0 1 1,4,7,10 * |
| Yearly (Jan 1) | 0 0 1 1 * |
| Weekdays, business hours | 0 9-17 * * 1-5 |
Conclusion
Cron expressions are deceptively simple — five fields, a handful of special characters, infinite scheduling power. The key is understanding how fields combine and knowing the quirks of your specific platform (Unix crontab vs. Quartz vs. AWS).
Bookmark this cheat sheet for quick reference. And when you need to build or validate a cron expression, use DevToolkit's visual Cron Expression Builder to get it right the first time.