What is CRON?

CRON is the standard job scheduler on Unix-like operating systems. It has been part of Unix since the late 1970s, and its syntax has become the universal language for expressing recurring schedules. Whether you need to run a database backup every night, clear temporary files every hour, or send a weekly report every Monday morning, CRON is how you tell the system when to do it.

The cron daemon (crond) runs in the background and checks a table of scheduled commands — the crontab — once per minute. When the current time matches a schedule entry, cron executes the associated command. There is no polling, no custom loop, and no code to maintain. You write the schedule, and cron handles the rest.

Today, CRON expressions are used far beyond traditional Unix systems. GitHub Actions, AWS EventBridge, Kubernetes CronJobs, and dozens of CI/CD platforms all accept cron syntax to define schedules. Understanding how to read and write these five-field expressions is a fundamental skill for any developer or system administrator.

The 5 Fields

A standard CRON expression consists of exactly five fields separated by spaces. Each field represents a unit of time and accepts a specific range of values:

Field Allowed Values Description
Minute 0–59 The minute of the hour when the job runs
Hour 0–23 The hour of the day (24-hour format)
Day of Month 1–31 The day of the month
Month 1–12 The month of the year
Day of Week 0–7 The day of the week (0 and 7 are both Sunday)

The fields are always in this order: minute, hour, day of month, month, day of week. Here is an annotated example:

30 9 * * 1-5
│  │ │ │ │
│  │ │ │ └── Day of week: 1-5 (Monday through Friday)
│  │ │ └──── Month: * (every month)
│  │ └────── Day of month: * (every day)
│  └──────── Hour: 9 (9 AM)
└────────── Minute: 30

This expression means: at 9:30 AM, Monday through Friday. It runs once per day on weekdays — a typical schedule for a morning report or notification.

Special Characters

CRON expressions support four special characters that give you flexible control over scheduling:

These characters can be combined within a single field. For example, 0,30 9-17 * * 1-5 runs at the top and bottom of every hour during business hours on weekdays — useful for polling an API or syncing data during the workday.

10 Common CRON Schedules

Here are ten CRON expressions that cover the most frequently needed schedules. You can copy these directly into your crontab or CI/CD configuration:

Expression Description
* * * * * Every minute
*/5 * * * * Every 5 minutes
0 * * * * Every hour (at minute 0)
0 0 * * * Every day at midnight
0 9 * * 1-5 Every weekday at 9:00 AM
0 0 * * 0 Every Sunday at midnight
0 0 1 * * First day of every month at midnight
0 6,18 * * * Twice daily at 6:00 AM and 6:00 PM
30 2 * * 0 Every Sunday at 2:30 AM (maintenance window)
0 0 1 1 * Once a year on January 1st at midnight

Most scheduling needs can be met by adapting one of these patterns. Change the hour, swap the day-of-week range, or add a step value to adjust the frequency.

Edge Cases to Watch

CRON expressions are straightforward once you understand the five fields, but a few edge cases catch people off guard. Knowing these will save you from debugging schedules that do not fire when you expect.

Day of week: 0 vs 7. Both 0 and 7 represent Sunday. The POSIX standard defines Sunday as 0, with Monday through Saturday as 1 through 6. Many cron implementations added 7 as an alias for Sunday because it feels more natural after 6 (Saturday). To avoid confusion, pick one and be consistent — most people use 0 for Sunday.

February and day-of-month limits. If you schedule a job for day 31 (0 0 31 * *), it will not run in months with fewer than 31 days. February never has more than 29 days, so 0 0 30 2 * will never execute. If you intend to run a job on the last day of every month, cron alone cannot express this — you will need a wrapper script that checks the date, or use a platform-specific extension.

Timezone awareness. Traditional Unix cron uses the system's local timezone. This means a server set to US Eastern time will interpret 0 9 * * * as 9:00 AM Eastern, which shifts relative to UTC during daylight saving time. Cloud platforms typically default to UTC. If your schedule is time-sensitive, always set the timezone explicitly using the CRON_TZ variable at the top of your crontab:

CRON_TZ=America/New_York
0 9 * * 1-5 /usr/local/bin/send-report.sh

Day-of-month AND day-of-week. When both the day-of-month and day-of-week fields are set to non-wildcard values, most cron implementations run the job when either condition is met, not when both are met. For example, 0 0 15 * 5 runs at midnight on the 15th of every month and on every Friday — not just on Fridays that fall on the 15th. This is one of the most commonly misunderstood behaviors in cron.

CRON in Different Environments

The five-field CRON syntax originated in Unix, but it has been adopted by many modern platforms. Each environment has its own quirks and extensions.

Linux crontab

The classic way to manage cron jobs. Edit your personal crontab with crontab -e and list entries with crontab -l. System-wide jobs go in /etc/crontab or as files in /etc/cron.d/. The system crontab format adds a sixth field for the username the command should run as:

# /etc/crontab format (note the username field)
0 3 * * * root /usr/local/bin/backup.sh

# User crontab format (no username field)
0 3 * * * /home/user/backup.sh

GitHub Actions

GitHub Actions uses the schedule trigger with standard five-field cron syntax. All schedules run in UTC and there is no way to change the timezone. GitHub may delay scheduled workflows during periods of high load, so they are not suitable for time-critical tasks:

on:
  schedule:
    - cron: '30 9 * * 1-5'  # 9:30 AM UTC, weekdays

AWS EventBridge (CloudWatch Events)

AWS uses a six-field cron format that adds a year field and replaces some features. AWS cron uses ? (no specific value) for either day-of-month or day-of-week — you must use ? in one of the two fields. All schedules run in UTC by default:

# AWS EventBridge cron (6 fields, note the ? and year)
cron(30 9 ? * MON-FRI *)  # 9:30 AM UTC, weekdays

Kubernetes CronJob

Kubernetes CronJobs use standard five-field cron syntax. The schedule is evaluated in the timezone of the kube-controller-manager, which is typically UTC. Starting with Kubernetes 1.27, you can set the .spec.timeZone field to an IANA timezone name:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-backup
spec:
  schedule: "0 2 * * *"
  timeZone: "America/New_York"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: backup-tool:latest
            command: ["/bin/sh", "-c", "run-backup.sh"]
          restartPolicy: OnFailure

Regardless of the platform, the core five-field syntax is the same. Learn it once, and you can schedule jobs anywhere.