Cron Expressions: A Complete Guide to Scheduling Tasks Like a Pro

Cron expressions are the scheduling language of the server world. This comprehensive guide teaches you the five-field syntax, walks through real-world scheduling examples, and covers how to combine cron with regex for advanced automation.

What Is a Cron Expression?

A cron expression is a compact string that defines a schedule for automated task execution. Originating from Unix's cron daemon in the 1970s, cron expressions have become the universal language for scheduling recurring jobs — from nightly database backups to hourly report generation, CI/CD pipeline triggers, and message queue consumers.

Despite their power, cron expressions have a reputation for being cryptic. A string like0 */6 * * 1-5 is perfectly clear once you learn the syntax, but opaque to the uninitiated. This guide breaks down every aspect of cron expressions so you can read, write, and debug them with confidence.

The 5-Field Syntax

A standard cron expression consists of five fields separated by spaces. Each field represents a unit of time:

┌───────── 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, where 0 and 7 = Sunday)
│ │ │ │ │
* * * * *
FieldAllowed ValuesSpecial Characters
Minute0–59* , - /
Hour0–23* , - /
Day of Month1–31* , - /
Month1–12 (or names)* , - /
Day of Week0–7 (or names)* , - /

Special Characters Explained

The real power of cron expressions comes from four special characters that let you define complex schedules in a single line:

Asterisk (*) — Every Value

Matches all possible values for a field. * * * * * runs every minute of every hour of every day.

Comma (,) — Value List

Specifies a list of discrete values. 0 9,12,18 * * * runs at 9:00 AM, 12:00 PM, and 6:00 PM every day.

Hyphen (-) — Range

Defines a contiguous range. 0 9-17 * * * runs at the top of every hour from 9 AM through 5 PM.

Slash (/) — Step

Defines intervals. */15 * * * * means "every 15 minutes" (0, 15, 30, 45). You can combine it with a starting value: 5/20 * * * * runs at minutes 5 and 25 and 45.

ℹ️

Some cron implementations support a sixth field for seconds (e.g., Spring's @Scheduled, Quartz Scheduler) and additional characters like L (last), W (weekday), and # (nth occurrence). These are non-standard extensions — always check your platform's documentation.

Common Cron Patterns

Here is a reference table of frequently used cron schedules that you can copy and adapt:

ExpressionDescription
* * * * *Every minute
*/5 * * * *Every 5 minutes
0 * * * *Every hour (at minute 0)
0 0 * * *Daily at midnight
0 9 * * 1-5Weekdays at 9:00 AM
0 0 * * 0Weekly on Sunday at midnight
0 0 1 * *Monthly on the 1st at midnight
0 0 1 1 *Yearly on January 1st at midnight
30 2 * * 1Every Monday at 2:30 AM
0 */6 * * *Every 6 hours (at 0:00, 6:00, 12:00, 18:00)
0 9-17 * * 1-5Every hour during business hours, weekdays only
0 0 15 * *15th of every month at midnight

Real-World Scheduling Examples

Let's look at how cron expressions are used in practice across different platforms:

Linux Crontab

# Edit the current user's crontab
crontab -e

# Database backup every night at 2:30 AM
30 2 * * * /usr/local/bin/backup-db.sh >> /var/log/backup.log 2>&1

# Clear temp files every Sunday at 4:00 AM
0 4 * * 0 find /tmp -type f -mtime +7 -delete

# Health check every 5 minutes
*/5 * * * * curl -s https://myapp.com/health | logger -t healthcheck

GitHub Actions

# .github/workflows/scheduled.yml
on:
  schedule:
    # Run tests every weekday at 8:00 AM UTC
    - cron: '0 8 * * 1-5'
    # Deploy staging every 6 hours
    - cron: '0 */6 * * *'

Kubernetes CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: report-generator
spec:
  schedule: "0 9 1 * *"    # 1st of every month at 9 AM
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: reporter
            image: myapp/reporter:latest
          restartPolicy: OnFailure
⚠️

GitHub Actions, Kubernetes, and most cloud schedulers run cron in UTC. If your job needs to run at 9 AM Eastern (ET), you must convert to UTC: 0 13 * * * (during EDT) or0 14 * * * (during EST). Daylight Saving Time makes this a recurring source of bugs.

Timezone Considerations

Timezone handling is one of the trickiest aspects of cron scheduling. Here are the key points to remember:

  • System cron (Linux/macOS) uses the system's local timezone by default. You can override it per-job with the TZ variable in some implementations:TZ=America/New_York 0 9 * * *.
  • Cloud schedulers (AWS EventBridge, GCP Cloud Scheduler) typically default to UTC but allow specifying a timezone in the configuration.
  • Daylight Saving Time (DST) can cause jobs to run twice, skip entirely, or shift by an hour. For critical jobs, consider scheduling in UTC to avoid DST surprises.
  • Distributed systems with servers across multiple time zones should always use UTC to prevent scheduling inconsistencies.

Testing Cron Expressions

Before deploying a cron schedule to production, always verify it does what you think it does. Here are reliable approaches:

1

Use a Cron Expression Tester

Online tools and local utilities let you paste a cron expression and see the next 5–10 execution times. This immediately reveals if your schedule matches your intention.

2

Dry-Run with Logging

Replace the actual command with a simple echo or log statement. Run it for a cycle and check the timestamps in your logs.

3

Use a Shorter Interval First

If your target schedule is daily, test with */2 * * * * (every 2 minutes) first to confirm the job executes correctly, then switch to the real schedule.

Common Mistakes to Avoid

Even experienced developers get tripped up by cron. Here are the most frequent mistakes:

  • Confusing day-of-month and day-of-week: In 0 0 1 * 5, does this mean "the 1st of every month" or "every Friday"? In standard cron, if both fields are set (not *), the job runs when either condition is true — not both.
  • Forgetting output redirection: Cron sends command output via email by default. If mail is not configured, output is silently lost. Always redirect:>> /var/log/job.log 2>&1.
  • Missing PATH: Cron jobs run with a minimal PATH. Commands like node orpython3 may not be found. Use absolute paths:/usr/local/bin/node script.js.
  • Not handling overlapping runs: If a job takes longer than the interval, multiple instances can run concurrently. Use file-based locks (flock) or a job runner that prevents overlap.
  • Ignoring timezone shifts: As mentioned above, DST changes can cause missed or duplicate executions. Schedule critical jobs in UTC.
💡

Add a comment above every cron entry explaining what it does in plain English. Six months from now,0 3 * * 0 will be meaningless without context, but# Weekly DB cleanup — Sundays at 3 AM is immediately clear.

Conclusion

Cron expressions are a concise, powerful way to define schedules for automated tasks. Once you understand the five-field syntax and the four special characters, you can express virtually any recurring schedule in a single line. The key to mastery is practice: use a cron tester to experiment, start with common patterns from the reference table, and always account for timezone and overlap issues in production.

Whether you're scheduling database backups, triggering CI pipelines, or automating report generation, solid cron skills will serve you throughout your career as a developer or system administrator.

🎯 Key Takeaways

  • Cron expressions have five fields: minute, hour, day-of-month, month, and day-of-week.
  • Master four special characters: * (every), , (list), - (range), and / (step).
  • Always test your expression with a cron tester before deploying to production.
  • Schedule critical jobs in UTC to avoid Daylight Saving Time surprises.
  • Use flock or similar locking to prevent overlapping job executions.
  • Comment every crontab entry — your future self will thank you.
← Retour au Blog