Skip to content
Cron Cookbook

GitHub Actions cron schedule, with examples

To run a GitHub Actions workflow on a schedule, add a schedule trigger under on with a five-field cron expression, like cron: '17 3 * * *' for 03:17 every day. The fields are the same as Unix cron, but the schedule runs in UTC unless you add a timezone, never more often than every 5 minutes, and only from the default branch.

Five things to know before you rely on it

  1. UTC unless you set a time zone

    Schedules run in UTC by default. Add timezone next to cron with an IANA name, like America/New_York, to use local time.
  2. Every 5 minutes at most

    The shortest interval GitHub runs is once every 5 minutes, so * * * * *doesn't run every minute.
  3. Runs start late, and can be dropped

    Under heavy load, most of all at the start of each hour, scheduled runs are delayed and some queued jobs are dropped.
  4. Only the default branch counts

    The workflow file has to be on the default branch, and the run uses that branch's latest commit.
  5. Public repos switch off after 60 days

    In a public repository with no activity for 60 days, GitHub disables scheduled workflows until you enable them again.

The schedule syntax

schedule takes a list, and each item has a cron key holding five fields: minute (0–59), hour (0–23), day of month (1–31), month (1–12 or JAN–DEC) and day of week (0–6 or SUN–SAT, with 0 as Sunday). Each field takes *, lists with ,, ranges with - and steps with /. Quote the expression: YAML treats a value starting with * as an alias.

GitHub doesn't support the shortcuts @yearly, @monthly, @weekly, @daily, @hourly or @reboot. Write 0 0 * * * instead of @daily, and use 0 rather than 7 for Sunday. To check what an expression does, paste it into the cron expression explainer, which also flags anything GitHub would reject.

GitHub Actions cron examples

ExpressionRunsUse
*/5 * * * *Every 5 minutes.The shortest interval GitHub allows
17 * * * *Every hour at :17.Hourly, off the busy top of the hour
*/15 9-17 * * 1-5Every 15 minutes from 09:00 through 17:45, Monday through Friday.Working hours on weekdays
30 5 * * 1-5At 05:30, Monday through Friday.A morning job on weekdays
15 4,5 * * *At 04:15 and 05:15 every day.GitHub's own example
0 9 * * MONAt 09:00 on Mondays.Weekly; names work in the month and weekday fields
0 0 1 * *At 00:00 on the 1st of every month.Monthly

Time zones: the timezone key

By default every schedule runs in UTC, so 30 5 * * 1-5 means 05:30 UTC, which is 01:30 in New York during daylight saving time. To run at a local time, add timezone with an IANA time zone name to the same list item as cron:

.github/workflows/report.yml
on:
  schedule:
    - cron: '30 5 * * 1-5'
      timezone: "America/New_York"

With a time zone set, the schedule follows daylight saving time. On the night clocks spring forward, a run that falls in the skipped hour moves to the next valid time: a 2:30 AM schedule runs at 3:00 AM. Workflows that don't set timezone stay in UTC, so they drift an hour against local time twice a year.

The 5-minute minimum

GitHub runs a scheduled workflow at most once every 5 minutes. The workflow still saves with * * * * * or */2 * * * *, but it won't run that often. */5 * * * * is the tightest schedule GitHub honours, and given the delays below, treat even that as approximate.

Why scheduled runs start late

The scheduleevent can be delayed when GitHub Actions is busy, and the start of every hour is the busiest time. When load is high enough, some queued jobs are dropped and don't run at all. A job set to 0 * * * * competes with every other hourly workflow; moving it to an odd minute, like 17 * * * *, makes a delay less likely.

Don't use it for exact timing

If a job has to run at a precise time, or must never be skipped, trigger it from a scheduler you control (through workflow_dispatch or repository_dispatch) instead of relying on schedule.

Only the default branch

A schedule only triggers if the workflow file exists on the repository's default branch, and the run uses the latest commit there. A schedule added on a feature branch does nothing until it's merged. Add workflow_dispatch: under on, as in the example workflow, so you can start the job by hand from the Actions tab to test it.

Notifications about scheduled runs go to the person who last changed the cron line in the workflow file.

When GitHub disables a schedule

In a public repository, GitHub automatically disables scheduled workflows when there has been no repository activity for 60 days. Scheduled workflows are also disabled by default in a fork of a public repository.

To turn one back on, open the Actions tab, pick the workflow and click Enable workflow, or run gh workflow enablewith the workflow's name or file name. A commit that changes the workflow's cron schedule, by someone with write access, also reactivates it.

Several schedules in one workflow

A workflow can list more than one cron. The expression that started a run is in github.event.schedule, so steps can behave differently for each schedule. This example from GitHub's documentation runs at 05:30 UTC Monday to Thursday and at 17:30 UTC on Tuesdays and Thursdays:

.github/workflows/schedule.yml
on:
  schedule:
    - cron: '30 5 * * 1,3'
    - cron: '30 5,17 * * 2,4'

jobs:
  test_schedule:
    runs-on: ubuntu-latest
    steps:
      - name: Not on Monday or Wednesday
        if: github.event.schedule != '30 5 * * 1,3'
        run: echo "Skipped on Monday and Wednesday"
      - name: Every time
        run: echo "This step always runs"

Need the field-by-field basics first? See the cron expression syntax guide.