epochkit
cron devops cheat sheet

Cron Expression Cheat Sheet

A complete reference for cron expression syntax: all 5 fields, special characters, 20 common patterns, and platform differences for GitHub Actions, Kubernetes, Vercel, and crontab.

Share X
Table of contents

TL;DR: A cron expression has 5 space-separated fields: minute hour day-of-month month day-of-week. Use * for “any”, / for step values, and , to list multiple values. 0 9 * * 1 runs at 9 AM every Monday.


Cron expression syntax

A standard cron expression is a string of five fields separated by spaces:

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

Each field accepts a number, a wildcard, or a combination of special characters.

The 5 fields

FieldAllowed valuesNotes
Minute0–59
Hour0–23UTC in most schedulers
Day of month1–31
Month1–12 or JAN–DEC
Day of week0–6 or SUN–SAT0 and 7 both mean Sunday in most systems

Special characters

CharacterMeaningExampleDescription
*Any* * * * *Every minute
,List0 9,17 * * *At 9 AM and 5 PM
-Range0 9-17 * * 1-5Every hour from 9–17 on weekdays
/Step*/15 * * * *Every 15 minutes
?No specific value0 0 ? * MONKubernetes/Quartz only; means “don’t care”
LLast0 0 L * *Last day of the month (Quartz only)
#Nth weekday0 0 * * 1#2Second Monday of the month (Quartz only)

20 common patterns

ExpressionDescription
* * * * *Every minute
*/5 * * * *Every 5 minutes
*/15 * * * *Every 15 minutes
0 * * * *Every hour
0 */2 * * *Every 2 hours
0 9 * * *Every day at 9 AM
0 0 * * *Every day at midnight
0 9,17 * * *At 9 AM and 5 PM daily
0 9 * * 1-5Every weekday at 9 AM
0 9 * * 1Every Monday at 9 AM
0 0 1 * *First day of every month at midnight
0 0 L * *Last day of the month (Quartz)
0 0 1 1 *January 1st at midnight
0 0 * * 0Every Sunday at midnight
30 8 * * 1-5Weekdays at 8:30 AM
0 0 1,15 * *1st and 15th of each month
0 6 * * 1Monday at 6 AM
*/30 9-17 * * 1-5Every 30 min during business hours
0 0 * * 5Every Friday at midnight
0 12 * * *Every day at noon

Platform differences

Each platform that uses cron syntax has its own quirks. Here is what to watch for.

GitHub Actions

GitHub Actions uses a 5-field standard cron in UTC. Place the schedule in your workflow YAML:

on:
  schedule:
    - cron: '0 9 * * 1-5'   # Weekdays at 9 AM UTC

Caveats:

  • The minimum interval is 5 minutes (shorter schedules are silently clamped).
  • Scheduled workflows on the default branch only.
  • GitHub may delay runs by up to several minutes under heavy load.
  • Workflows on a repository with no activity in 60 days are automatically disabled.

Kubernetes CronJob

Kubernetes uses standard 5-field cron, also in UTC by default:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: daily-cleanup
spec:
  schedule: "0 2 * * *"    # 2 AM UTC daily
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: cleanup
              image: my-cleanup-image
          restartPolicy: OnFailure

Caveats:

  • Set spec.timeZone: "America/New_York" (Kubernetes ≥ 1.27) to use a non-UTC timezone.
  • spec.concurrencyPolicy: Forbid prevents overlap if the previous job is still running.
  • spec.startingDeadlineSeconds controls how late a missed job can start.

Vercel cron

Vercel Cron Jobs (available on Pro and Enterprise) configure scheduled function invocations via vercel.json:

{
  "crons": [
    {
      "path": "/api/cron/daily-report",
      "schedule": "0 8 * * *"
    }
  ]
}

Caveats:

  • Maximum 2 cron jobs on Pro, 40 on Enterprise.
  • The invoker sends a GET request to your route; authenticate with CRON_SECRET.
  • All schedules run in UTC.
  • Minimum interval is 1 minute.

Standard crontab

The classic Unix crontab (edit with crontab -e):

# minute  hour  day  month  weekday  command
0        9     *    *      1-5      /usr/local/bin/send-report.sh
*/5      *     *    *      *        /usr/bin/check-status.sh >> /var/log/check.log 2>&1

Caveats:

  • Runs in the timezone of the server unless CRON_TZ or TZ is set at the top of the file: TZ=America/New_York.
  • Environment variables are minimal — set PATH explicitly in the crontab or script.
  • Output goes to the local user’s mail unless redirected.

Common mistakes and how to debug

Mistake: wrong timezone Most hosted cron schedulers run in UTC. A job set to 0 9 * * * runs at 9 AM UTC, which is 2 AM Pacific or 5 AM Eastern. Always specify and document the timezone.

Mistake: confusing */n with a specific value */15 means “every 15 minutes starting from 0” (i.e., 0, 15, 30, 45). It is not the same as 15 (which fires only at minute 15).

Mistake: day-of-month + day-of-week interaction When both the day-of-month and day-of-week fields are set to a non-wildcard value, most cron implementations (including Vixie cron) treat them as OR, not AND. 0 0 1 * 1 fires on both the 1st of every month and every Monday.

Mistake: running more often than intended * * * * * runs every minute, 1440 times per day. Add the hour field: 0 * * * * runs once per hour.

Debugging approach:

  1. Use epochkit’s Cron Builder to paste your expression and see the next 5 execution times.
  2. Check logs immediately after the expected fire time — many platforms log missed runs.
  3. If unsure about timezone, add a one-time job that logs the current time and compare.
  4. On Linux, grep CRON /var/log/syslog shows cron daemon output.

Need to build or validate a cron expression interactively? epochkit’s cron builder shows a human-readable description of any expression and previews the next 5 scheduled runs — no sign-up required.