Cron Syntax Explained, with 15 Ready-to-Use Examples

Learn the five fields of a cron expression and the special characters *, /, - and comma, then copy tested schedules for crontab, Kubernetes and GitHub Actions.

· 4 min read

A cron expression is five fields separated by spaces that tell a scheduler when to run a job. Once you can read the fields, every schedule from "every 5 minutes" to "9 AM on weekdays" becomes easy to write. This guide covers the syntax, the four special characters, and the mistakes that make jobs run at the wrong time.

The five fields

┌───────────── minute        (0–59)
│ ┌─────────── hour          (0–23)
│ │ ┌───────── day of month  (1–31)
│ │ │ ┌─────── month         (1–12)
│ │ │ │ ┌───── day of week   (0–7, Sunday is 0 or 7)
│ │ │ │ │
* * * * *  command-to-run

A job runs whenever the current time matches all of the fields, with one exception covered below. So 30 2 * * * means "minute 30 of hour 2, any day, any month, any weekday", or 2:30 AM every day.

The special characters

CharacterMeaningExampleReads as
*Any value* * * * *Every minute
,A list0 9,17 * * *At 9:00 and 17:00
-A range0 9 * * 1-5At 9:00, Monday to Friday
/A step*/15 * * * *Every 15 minutes

You can combine them. */5 9-17 * * 1-5 means every 5 minutes from 9:00 to 17:55 on weekdays.

Many schedulers also accept names like MON-FRI or JAN, and shortcuts like @daily or @hourly. Plain numbers work everywhere, so they're the safer choice.

If you're not sure what an expression does, paste it into the cron explainer to get a plain-English description before you ship it.

15 common schedules

Each link opens a page with the field-by-field breakdown and the next run times.

ScheduleExpression
Every minute* * * * *
Every 5 minutes*/5 * * * *
Every 15 minutes*/15 * * * *
Every 30 minutes*/30 * * * *
Every hour0 * * * *
Every 6 hours0 */6 * * *
Every day at midnight0 0 * * *
Every day at 2 AM0 2 * * *
Twice a day0 0,12 * * *
Every weekday at 9 AM0 9 * * 1-5
Every Monday0 0 * * 1
Every 5 minutes during business hours*/5 9-17 * * 1-5
First day of every month0 0 1 * *
Every quarter0 0 1 1,4,7,10 *
Every year0 0 1 1 *

There are more in the full list of cron expression examples.

Mistakes that bite

Forgetting the minute field

* 9 * * * doesn't mean "at 9 AM". It means every minute from 9:00 to 9:59, which is 60 runs. To run once at 9 AM, set the minute: 0 9 * * *.

Day of month and day of week together

When both the day-of-month and day-of-week fields are restricted, classic cron runs the job when either one matches, not both. 0 0 13 * 5 runs on every 13th and every Friday, not only on Friday the 13th. If you need both conditions, schedule on one field and check the other inside the script.

Steps don't carry over between hours

*/7 * * * * runs at minutes 0, 7, 14 … 56, then at 0 again. The gap between :56 and :00 is 4 minutes, not 7. Steps restart at each hour (or day, for the hour field), so pick a step that divides evenly into 60 or 24 if you need even spacing.

Time zones

Cron uses the time zone of the machine or service running it, and on servers that's often UTC. GitHub Actions schedules are always in UTC. Kubernetes CronJobs use the controller's time zone unless you set spec.timeZone. A "9 AM" job written on a laptop in New York can easily run at 4 or 5 AM local time once it's deployed. The time zone converter helps you work out the UTC hour.

Using cron in common tools

crontab

Edit your user's crontab with crontab -e and add one line per job. Redirect output so failures leave a trace:

*/5 * * * * /usr/local/bin/sync.sh >> /var/log/sync.log 2>&1

Cron runs with a minimal environment, so use absolute paths for commands and files.

Kubernetes CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-report
spec:
  schedule: "0 2 * * *"
  timeZone: "Etc/UTC"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: report
              image: my-registry/report:latest
          restartPolicy: OnFailure

concurrencyPolicy: Forbid stops a new run from starting while the previous one is still going.

GitHub Actions

on:
  schedule:
    - cron: '0 9 * * 1-5'  # 09:00 UTC on weekdays

The shortest interval GitHub allows is every 5 minutes, and scheduled runs can start late when GitHub is busy, so don't rely on exact timing.

Quick reference

  • Five fields: minute, hour, day of month, month, day of week.
  • * any, , list, - range, / step.
  • Always set the minute field for "once at hour X" jobs.
  • Check which time zone your scheduler uses before you deploy.

Writing a new schedule? Check it with the cron explainer first.