Expert ReviewedUpdated 2025developer
developer
10 min readJune 11, 2024Updated Oct 26, 2025

Cron Expressions Explained: A Developer’s Complete Guide

Learn cron expression syntax from basics to advanced patterns. Schedule jobs with confidence using practical examples for common scheduling scenarios.

Cron is the time-based job scheduler in Unix-like systems. It uses a compact expression format to specify when commands should run—every minute, every day at midnight, every Monday at 3 AM, or countless other schedules. This guide demystifies cron syntax so you can schedule any job with confidence.

Key Takeaways

  • 1
    Standard cron has 5 fields: minute, hour, day-of-month, month, day-of-week
  • 2
    Special characters: * (every), , (list), - (range), / (step), L (last), # (nth)
  • 3
    Common patterns: */5 * * * * (every 5 min), 0 0 * * * (daily midnight), 0 9 * * 1-5 (weekdays 9 AM)
  • 4
    Debug with absolute paths, output redirection, and checking cron logs
  • 5
    Use flock to prevent overlapping runs and log everything with timestamps

Cron Expression Anatomy

A standard cron expression has 5 fields, each representing a time unit. Some systems (like Quartz) add a 6th field for seconds. Here's the basic format:
# Standard 5-field cron format
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
│ │ │ │ │
* * * * *  command_to_execute
Cron field reference
FieldAllowed ValuesSpecial Characters
Minute0-59* , - /
Hour0-23* , - /
Day of Month1-31* , - / ? L W
Month1-12 or JAN-DEC* , - /
Day of Week0-6 or SUN-SAT* , - / ? L #
Day of week: 0 and 7 both represent Sunday. Some systems accept 3-letter abbreviations (MON, TUE, etc.) for months and days.

2Special Characters Explained

Beyond simple numbers, cron uses special characters to create flexible schedules.
Special character reference
CharacterMeaningExample
*Any/every value* in hour = every hour
,List of values1,15,30 = 1st, 15th, 30th
-Range of values1-5 = 1, 2, 3, 4, 5
/Step/interval*/15 = every 15 units
?No specific value (day fields)Use ? when day-of-month OR day-of-week is set
LLast (day fields)L in day-of-month = last day of month
WNearest weekday15W = weekday nearest to 15th
#Nth occurrence2#3 = 3rd Monday (day 2, 3rd occurrence)
Example: Step Values in Action

Scenario

*/10 * * * * means run every 10 minutes (0, 10, 20, 30, 40, 50)

Solution

The */10 in minute field divides 60 by 10, running at each step.

Not all cron implementations support all special characters. Standard cron (crontab) supports * , - /. Extended features like L, W, # are available in Quartz, Spring, and other schedulers.

Common Scheduling Patterns

Here are the most frequently used cron expressions. Copy these as starting points for your schedules.
Common cron schedules
ExpressionSchedule
* * * * *Every minute
*/5 * * * *Every 5 minutes
0 * * * *Every hour (at minute 0)
0 0 * * *Daily at midnight
0 9 * * *Daily at 9:00 AM
0 9 * * 1-5Weekdays at 9:00 AM
0 0 * * 0Every Sunday at midnight
0 0 1 * *1st of every month at midnight
0 0 1 1 *January 1st at midnight (yearly)
30 4 * * *Daily at 4:30 AM
0 */2 * * *Every 2 hours
0 9-17 * * 1-5Hourly 9AM-5PM, weekdays

Translate Cron Expressions Instantly

Paste any cron expression and see a human-readable explanation.

Open Cron Translator

4Advanced Scheduling Patterns

Complex schedules often combine multiple patterns. Here are some real-world examples.
Advanced scheduling patterns
ExpressionMeaning
0 9,12,18 * * *9 AM, 12 PM, and 6 PM daily
0 0 15,L * *15th and last day of month at midnight
0 0 * * 1#1First Monday of every month
0 0 * * 5LLast Friday of every month
0 0 1-7 * 1First Monday of month (1st-7th that is Monday)
*/30 9-17 * * 1-5Every 30 min during business hours
0 0 1 */3 *Quarterly (Jan, Apr, Jul, Oct 1st)
0 4 8-14 * 02nd Sunday of month at 4 AM
When both day-of-month and day-of-week are specified, most cron implementations use OR logic (runs if either matches). Use ? to explicitly ignore one field in systems that support it.

5Working with crontab

The crontab command manages your cron schedules on Unix/Linux systems.
# Edit your crontab
crontab -e

# List current crontab entries
crontab -l

# Remove all crontab entries (use with caution!)
crontab -r

# Edit another user's crontab (requires root)
sudo crontab -u username -e
# Example crontab file content
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
MAILTO=admin@example.com

# Backup database every night at 2 AM
0 2 * * * /home/user/scripts/backup.sh >> /var/log/backup.log 2>&1

# Clear temp files every Sunday at 4 AM
0 4 * * 0 rm -rf /tmp/cache/*

# Health check every 5 minutes
*/5 * * * * curl -s https://example.com/health > /dev/null
Always redirect output (>> logfile 2>&1) to prevent cron from sending emails for every run. Set MAILTO="" to disable emails entirely.

6Debugging Cron Jobs

Cron jobs fail silently if not properly configured. Here's how to troubleshoot.
  1. 1Check cron logs: /var/log/cron or /var/log/syslog (grep CRON)
  2. 2Use absolute paths: Cron has minimal PATH. Use /usr/bin/python not python.
  3. 3Redirect output: >> /path/to/log.log 2>&1 captures stdout and stderr.
  4. 4Test command manually: Run the exact command in terminal first.
  5. 5Check permissions: Script must be executable (chmod +x script.sh).
  6. 6Verify cron is running: systemctl status cron or service cron status.
  7. 7Environment variables: Cron has minimal env. Source profiles if needed.
# Debug wrapper for cron jobs
#!/bin/bash
# Save as /home/user/scripts/cron-wrapper.sh

# Log start time
echo "=== Job started at $(date) ==="

# Load environment
source /home/user/.bashrc

# Run actual command
/home/user/scripts/my-job.sh

# Log completion
echo "=== Job completed at $(date) with exit code $? ==="
Common gotcha: Scripts work in terminal but fail in cron. This is almost always a PATH or environment issue. Add "env > /tmp/cronenv.txt" to your cron job to see what environment cron provides.

7Beyond Cron: Modern Alternatives

While cron is universal, modern systems offer alternatives with additional features.
Cron alternatives comparison
ToolBest ForKey Features
systemd timersLinux serversBetter logging, dependency handling
AWS EventBridgeCloud workloadsServerless, managed, event-driven
Kubernetes CronJobsContainer workloadsPod-based, retries, history
Celery BeatPython appsDatabase-backed, dynamic schedules
GitHub ActionsCI/CD workflowsschedule trigger with cron syntax
node-cronNode.js appsIn-process, second precision
# GitHub Actions scheduled workflow example
name: Daily Backup
on:
  schedule:
    # Runs at 2 AM UTC every day
    - cron: '0 2 * * *'
jobs:
  backup:
    runs-on: ubuntu-latest
    steps:
      - name: Run backup
        run: echo "Backup complete"

8Cron Best Practices

Follow these guidelines to create reliable, maintainable cron jobs.
  • Use comments: # Daily backup - added 2024-01-15 by John
  • Log everything: Redirect output to timestamped log files
  • Use lock files: Prevent overlapping runs with flock or similar
  • Set timeouts: Kill jobs that run too long to prevent pile-ups
  • Monitor failures: Alert on exit codes != 0 or missing logs
  • Stagger timing: Avoid all jobs at :00 to reduce load spikes
  • Document schedules: Maintain a wiki/doc of all scheduled jobs
  • Test in staging: Verify cron jobs work before production
# Cron job with best practices
# Runs every hour, prevents overlapping, logs with timestamps

0 * * * * /usr/bin/flock -n /tmp/myjob.lock \
  /home/user/scripts/myjob.sh >> /var/log/myjob/$(date +\%Y-\%m-\%d).log 2>&1
Use flock -n (non-blocking) to skip a run if the previous one is still going, or flock (blocking) to queue runs. This prevents the "piling up" problem.

Frequently Asked Questions

What does * mean in a cron expression?
The asterisk (*) means ’every’ or ’any value.’ For example, * in the hour field means every hour. * in the day field means every day. The expression * * * * * runs every minute because all five fields are wildcards.
How do I run a cron job every 5 minutes?
Use */5 in the minute field: */5 * * * * command. The / operator creates steps. */5 means 0, 5, 10, 15, ... 55. For every 10 minutes use */10, for every 15 minutes use */15.
Why isn’t my cron job running?
Common causes: 1) PATH issues - use absolute paths like /usr/bin/python. 2) Permission denied - make script executable with chmod +x. 3) Wrong user - check which user’s crontab the job is in. 4) Cron service stopped - run systemctl status cron. 5) No output capture - add >> /tmp/log.txt 2>&1 to see errors.
What’s the difference between cron and crontab?
Cron is the daemon (background service) that runs scheduled jobs. Crontab (cron table) is the file containing the schedule entries, and also the command used to edit that file. You use ’crontab -e’ to edit your crontab file, which cron reads to know what jobs to run.
Can I run cron jobs at second precision?
Standard cron only supports minute precision. For second-level scheduling, use alternatives: sleep workarounds (run every minute, loop with sleeps), systemd timers (support seconds), or application-level schedulers like node-cron or Celery Beat that support seconds.