Understanding Cron Expressions: A Complete Guide to Scheduling

Learn how to read, write, and debug cron expressions for scheduling automated tasks on any platform.

The Quick Answer

A cron expression is a string of five fields that defines a recurring schedule. Each field represents a unit of time:

┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
│ │ │ │ │
* * * * *

Each * means "every" for that field. So * * * * * means "every minute of every hour of every day."

How to Read a Cron Expression

Read cron expressions right to left, starting from the most restrictive non-* field.

Example: 30 4 1,15 * *

  1. Day of week: * → any day of the week
  2. Month: * → every month
  3. Day of month: 1,15 → on the 1st and 15th
  4. Hour: 4 → at 4 AM
  5. Minute: 30 → at minute 30

Result: At 4:30 AM on the 1st and 15th of every month.

Special Characters

Cron supports four operators that give you precision beyond simple values:

Character Meaning Example What It Does
* Every value * * * * * Every minute
, List 1,15 * * * * Minute 1 and minute 15
- Range 0 9-17 * * * Every hour from 9 AM to 5 PM
/ Step */10 * * * * Every 10 minutes

You can combine them:

  • 1-5 → 1, 2, 3, 4, 5
  • */15 → every 15th value (0, 15, 30, 45 for minutes)
  • 1,15,30 → specific values
  • 10-30/5 → every 5th value from 10 to 30 (10, 15, 20, 25, 30)

Common Cron Expressions

These cover the schedules most people need:

Schedule Expression Notes
Every minute * * * * * Useful for testing only
Every 5 minutes */5 * * * * Monitoring, health checks
Every 15 minutes */15 * * * * Data syncs
Every hour at :00 0 * * * * Hourly reports
Every day at midnight 0 0 * * * Daily backups, log rotation
Every day at 9 AM 0 9 * * * Morning reports
Weekdays at 9 AM 0 9 * * 1-5 Business-hours tasks
Every Monday at 8 AM 0 8 * * 1 Weekly summaries
First of each month 0 0 1 * * Monthly billing, cleanup
Every Sunday at 2 AM 0 2 * * 0 Weekly maintenance windows
Twice daily (9 AM, 6 PM) 0 9,18 * * * Morning and evening runs
Every quarter (Jan, Apr, Jul, Oct) 0 0 1 1,4,7,10 * Quarterly reports

Where Cron Expressions Are Used

Cron syntax originated in Unix (1975) but is now the standard scheduling format across platforms:

  • Linux/macOScrontab -e to edit scheduled jobs
  • AWS EventBridge / CloudWatch — trigger Lambda, ECS, Step Functions (uses a 6-field variant)
  • GitHub Actions — the schedule trigger accepts cron expressions
  • Kubernetes CronJobs — recurring containerized workloads
  • CI/CD systems — Jenkins, GitLab CI, CircleCI pipeline schedules
  • Frameworks — Spring @Scheduled (Java), Laravel scheduler (PHP), Celery beat (Python), node-cron (Node.js)
  • Cloud services — Google Cloud Scheduler, Azure Functions timer triggers, Vercel cron

5-Field vs. 6-Field Cron

Standard Unix cron uses 5 fields. Some systems add a seconds field at the beginning:

// 5-field (standard)
minute  hour  day  month  weekday

// 6-field (with seconds)
second  minute  hour  day  month  weekday

Systems that use 6-field cron include Quartz (Java), Spring @Scheduled, and AWS EventBridge. If you paste a 5-field expression into a 6-field system, the fields will be misinterpreted.

Tip: Count the fields first. If there are 6, the first one is seconds.

Cron Time Zones

By default, cron runs in the server's time zone. This causes a common class of bugs:

  • Your server is in UTC
  • You write 0 9 * * * expecting 9 AM local time
  • The job actually runs at 9 AM UTC (which may be 4 AM EST or 1 AM PST)

Solutions:

  1. Set CRON_TZ at the top of your crontab (supported on many Linux distributions):

    CRON_TZ=America/New_York
    0 9 * * * /path/to/script.sh
    
  2. Calculate the UTC offset manually and adjust the hour field.

  3. Check your platform's docs. GitHub Actions and Kubernetes CronJobs always use UTC. AWS EventBridge lets you set a time zone per rule.

Watch for DST transitions. When clocks spring forward, a 2:30 AM cron job may be skipped. When they fall back, it may run twice. Schedule critical jobs outside the 1:00–3:00 AM window if DST matters.

Common Mistakes

1. Hour 24 Does Not Exist

Midnight is hour 0, noon is 12, 11 PM is 23. The value 24 is invalid and will cause an error or be silently ignored.

2. Day-of-Week Numbering

Sunday is 0 (or 7 on most systems). Monday is 1, Saturday is 6. Some Java-based systems (Quartz) use 1 for Sunday and 7 for Saturday. Always verify with your platform.

3. OR Logic for Day Fields

If both day-of-month and day-of-week are set to non-* values, standard cron runs the job when either matches:

# Runs on the 15th AND on every Monday — not just Mondays that fall on the 15th
0 0 15 * 1

This surprises many people. If you need "the first Monday of each month," use a script-level check instead.

4. Overlapping Runs

If a job takes 10 minutes but runs every 5, two instances will overlap. Prevent this with a lock file:

flock -n /tmp/myjob.lock /path/to/script.sh

Or add a check at the start of your script.

5. Missing PATH

Cron runs with a minimal environment. Commands that work in your terminal may fail because /usr/local/bin or other paths are not included. Use absolute paths:

# Bad
0 * * * * python3 myscript.py

# Good
0 * * * * /usr/bin/python3 /home/user/scripts/myscript.py

6. No Output Capture

By default, cron sends output (stdout and stderr) as email. If no mail system is configured, output is lost silently. Always redirect:

0 0 * * * /path/to/backup.sh >> /var/log/backup.log 2>&1

Tips for Production Cron Jobs

  1. Test with * * * * * — run every minute first to confirm the command works, then switch to the real schedule.
  2. Use absolute paths — for both the command and any files it reads or writes.
  3. Set MAILTO — put [email protected] at the top of your crontab to receive failure notifications.
  4. Log everything — append >> /var/log/myjob.log 2>&1 to capture both stdout and stderr.
  5. Comment your crontab — add a line above each entry explaining its purpose.
  6. Monitor for failures — a cron job that silently fails for weeks is worse than no automation at all.
  7. Use lock files — prevent overlapping runs for long-running jobs.
  8. Document the time zone — add a comment noting which time zone the schedule assumes.

Worked Example: Setting Up a Daily Backup

Goal: Back up a database every day at 3:15 AM server time (UTC), log the output, and prevent overlapping runs.

Crontab entry:

# Daily database backup — 3:15 AM UTC
# Owner: ops team | Last updated: 2026-02-01
15 3 * * * flock -n /tmp/db-backup.lock /opt/scripts/backup-db.sh >> /var/log/db-backup.log 2>&1

How to read it:

  • Minute 15, hour 3 → 3:15 AM
  • * * * → every day, every month, every day of the week
  • flock -n → skip this run if the previous one is still going
  • >> ... 2>&1 → append all output to the log file

Debugging Cron Jobs

When a cron job is not running, check these in order:

  1. Is the expression valid? Paste it into a cron validator to verify syntax and see next run times.
  2. Is cron running? Check with systemctl status cron (or crond on some systems).
  3. Is the crontab loaded? Run crontab -l to confirm your entry is listed.
  4. Can the command run manually? Execute the exact command from the crontab in your terminal.
  5. Check permissions. The script needs execute permission (chmod +x script.sh).
  6. Check the mail. Run mail to see if cron sent error messages.
  7. Check syslog. Look in /var/log/syslog or /var/log/cron for execution records.

Cron Alternatives

Cron handles simple recurring schedules well. For more complex needs, consider:

  • systemd timers — built into modern Linux, support calendar expressions and dependency ordering
  • at — for one-time scheduled commands (at now + 2 hours)
  • Task schedulers — Celery (Python), Sidekiq (Ruby), Bull (Node.js) for application-level job queues
  • Cloud schedulers — AWS EventBridge, Google Cloud Scheduler, Azure Timer Triggers for serverless and managed scheduling

Cron remains the right choice when you need a simple, reliable, system-level recurring schedule without additional infrastructure.

Frequently Asked Questions

What is a cron expression?

A cron expression is a string of five space-separated fields that defines a recurring schedule. The fields represent minute, hour, day of month, month, and day of week. Systems use cron expressions to automate tasks like backups, reports, and data syncs.

What does the asterisk (*) mean in cron?

The asterisk means "every possible value" for that field. In the hour field, * means every hour (0 through 23). In the day-of-week field, * means every day of the week.

How do I run a cron job every 5 minutes?

Use */5 * * * *. The /5 is a step value that triggers at every 5th minute: 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55.

What is the difference between 5-field and 6-field cron?

Standard Unix cron uses 5 fields (minute, hour, day, month, weekday). Some platforms add a seconds field at the beginning, making it 6 fields. Quartz (Java), Spring, and AWS EventBridge use this extended format.

What time zone does cron use?

By default, the server's local time zone. On most cloud servers, this is UTC. You can override it with the CRON_TZ variable in your crontab, or check your platform's documentation for time zone settings.

Can I schedule a cron job for the last day of the month?

Not with standard cron syntax alone. A common workaround is to schedule the job for days 28-31 and add a check in your script: [ $(date +%d -d tomorrow) -eq 1 ] && run_job.

What does 0 0 * * 0 mean?

At midnight (00:00) every Sunday. Minute 0, hour 0, any day of month, any month, day of week 0 (Sunday).

Why is my cron job not running?

Check these common causes: invalid syntax, missing absolute paths, no execute permissions on the script, environment variables not loaded (cron does not source your shell profile), and time zone mismatches.

How do I list my current cron jobs?

Run crontab -l in your terminal. To edit, run crontab -e. To view another user's crontab (requires root), run crontab -u username -l.

Is day 0 Sunday or Monday?

In standard cron, 0 is Sunday. Monday is 1, Saturday is 6. The value 7 is also accepted as Sunday on most systems. Quartz-based systems differ — check your platform.

What happens if both day-of-month and day-of-week are set?

On standard cron, the job runs when either condition matches (OR logic), not both. This is a common source of confusion.

Can I schedule every 90 minutes with cron?

Not directly, because step values work within single fields and minutes max out at 59. You need two crontab entries that together create a 90-minute cycle, or use a different scheduler with interval support.

Decode Any Expression

Cron Expression Humanizer

Paste a cron expression and see it explained in plain English, with upcoming run times.

Open Humanizer
Build Your Expression

Crontab Generator

Build cron expressions visually with presets and see next run times.

Open Generator
Validate Your Expression

Cron Schedule Validator

Test your cron expression and see when it will run next.

Open Validator

Related Tools