Understanding Cron Syntax
A cron expression is a string of five (or six) fields that defines when a scheduled job runs. Each field represents a unit of time, and together they form a precise schedule that repeats automatically.
The standard five-field format:
┌───────────── minute (0–59)
│ ┌───────────── hour (0–23)
│ │ ┌───────────── day of month (1–31)
│ │ │ ┌───────────── month (1–12)
│ │ │ │ ┌───────────── day of week (0–7, where 0 and 7 are Sunday)
│ │ │ │ │
* * * * *
Some systems (like AWS EventBridge, Quartz Scheduler) add a seconds field before the minute, making it six fields total.
Special Characters Explained
| Character | Meaning | Example |
|---|---|---|
* |
Any value | * * * * * — every minute |
, |
List of values | 1,15,30 in minute — at 1st, 15th, 30th minute |
- |
Range | 9-17 in hour — from 9am to 5pm |
/ |
Step | */5 in minute — every 5 minutes |
L |
Last | L in day-of-month — last day of the month |
# |
Nth weekday | 2#3 — third Tuesday of the month |
? |
No specific value | Used in day-of-month or day-of-week when the other is set |
The Most Common Cron Schedules
These are the patterns developers reach for most often:
Every Minute
* * * * *
Rarely used in production. Avoid this for anything with meaningful I/O — it runs 1,440 times a day.
Every 5 Minutes
*/5 * * * *
The most common schedule for health checks, polling tasks, and lightweight background jobs.
Every 15 Minutes
*/15 * * * *
Good for syncing data or checking for updates without overwhelming a service.
Every Hour (at the top)
0 * * * *
Runs at minute 0 of every hour: 1:00, 2:00, 3:00...
Every Hour (at a specific minute)
30 * * * *
Runs at minute 30 of every hour: 1:30, 2:30, 3:30... Useful to offset from the top of the hour when servers are busy.
Once a Day at Midnight
0 0 * * *
Daily cleanup jobs, report generation, cache invalidation.
Once a Day at 2 AM
0 2 * * *
Database backups, log rotation — scheduled during off-peak hours.
Every Day at 8 AM and 6 PM
0 8,18 * * *
Twice-daily summaries or digest emails.
Every Weekday at 9 AM
0 9 * * 1-5
Business-hours-only jobs: send morning reports, sync calendars.
Every Monday at Midnight
0 0 * * 1
Weekly tasks: generate weekly summaries, clean up old sessions.
First Day of Every Month
0 0 1 * *
Monthly billing cycles, subscription renewals, report generation.
Last Day of Every Month
0 0 L * *
Note: L is supported in Quartz and some extended cron parsers, but not standard Unix crontab. For standard cron, use a script that checks the date.
Complete Reference Table
| Schedule | Expression | Notes |
|---|---|---|
| Every minute | * * * * * |
1,440 runs/day |
| Every 5 min | */5 * * * * |
288 runs/day |
| Every 10 min | */10 * * * * |
144 runs/day |
| Every 15 min | */15 * * * * |
96 runs/day |
| Every 30 min | */30 * * * * |
48 runs/day |
| Every hour | 0 * * * * |
24 runs/day |
| Every 2 hours | 0 */2 * * * |
12 runs/day |
| Every 6 hours | 0 */6 * * * |
4 runs/day |
| Daily at midnight | 0 0 * * * |
1 run/day |
| Daily at noon | 0 12 * * * |
1 run/day |
| Every weekday | 0 0 * * 1-5 |
5 runs/week |
| Every weekend | 0 0 * * 6,0 |
2 runs/week |
| Weekly (Monday) | 0 0 * * 1 |
1 run/week |
| Monthly (1st) | 0 0 1 * * |
1 run/month |
| Monthly (15th) | 0 0 15 * * |
1 run/month |
| Yearly (Jan 1) | 0 0 1 1 * |
1 run/year |
Cron in Different Environments
The base syntax is the same, but each platform has quirks.
Linux / Unix crontab
# Edit your crontab
crontab -e
# View current crontab
crontab -l
# System-wide crontabs live in /etc/cron.d/
# Each line: minute hour day month weekday user command
*/5 * * * * deploy /usr/bin/python3 /opt/scripts/check.py
GitHub Actions
on:
schedule:
- cron: '0 9 * * 1-5' # Weekdays at 9 AM UTC
GitHub Actions uses UTC. The minimum interval is every 5 minutes, and jobs may be delayed during heavy load.
AWS EventBridge (CloudWatch Events)
AWS uses a six-field format with seconds first, and minutes second:
cron(0 12 * * ? *) # Every day at noon UTC
cron(0/5 * * * ? *) # Every 5 minutes
Note: AWS uses ? in place of * for day-of-month or day-of-week when the other is specified.
Node.js (node-cron)
const cron = require('node-cron');
// Every 5 minutes
cron.schedule('*/5 * * * *', () => {
console.log('Running task every 5 minutes');
});
// Every weekday at 9 AM
cron.schedule('0 9 * * 1-5', () => {
sendMorningReport();
});
Python (APScheduler)
from apscheduler.schedulers.blocking import BlockingScheduler
scheduler = BlockingScheduler()
@scheduler.scheduled_job('cron', hour=9, minute=0, day_of_week='mon-fri')
def send_daily_report():
print('Sending report...')
scheduler.start()
Common Mistakes
Not using UTC — Most cron systems run in UTC. A job at "midnight" may fire at noon your time. Always check which timezone your scheduler uses and document it explicitly.
Using * in every field — * * * * * fires every minute. If your job takes more than 60 seconds to run, overlapping executions will pile up. Add locking or use */5 at minimum.
Day-of-month and day-of-week interactions — In standard cron, if both are set (not *), the job runs when either condition is true, not both. This is the source of many unexpected extra runs. Use ? in systems that support it to explicitly say "I don't care about this field."
No error alerting — A failed cron job often fails silently. Always redirect stderr to a log file and set up monitoring or alerting for failed runs.
# Capture both stdout and stderr
*/5 * * * * /opt/script.sh >> /var/log/script.log 2>&1
FAQ
How do I run a cron job every 2 hours starting at midnight?
0 */2 * * * — This runs at 0:00, 2:00, 4:00, ... 22:00.
How do I run a cron job at 9:30 AM and 3:30 PM?
30 9,15 * * *
Can a cron expression run on the last weekday of the month? Not in standard cron. You need a script that calculates this, or use an extended scheduler like Quartz.
What's the smallest interval cron supports?
Standard cron supports down to every minute (* * * * *). For sub-minute intervals, use a process manager, a message queue, or a scheduler that supports seconds.
→ Use the Crontab Generator to build and validate any cron expression visually — no syntax memorization needed.