GitHub Actions Cron
GitHub Actions uses standard 5-field Unix cron syntax in `on.schedule.cron`. The two things that catch people: the minimum interval is 5 minutes (not 1 like other platforms), and scheduled workflows can be delayed by tens of minutes during periods of high load. Schedules default to UTC, but since March 2026 you can add an optional `timezone:` field (IANA name) alongside each cron entry.
Quick reference
- Fields
- minute hour day-of-month month day-of-week
- Minute range
- 0–59
- Hour range
- 0–23
- Day-of-month range
- 1–31
- Month range
- 1–12 (GitHub's docs show numeric only; prefer it)
- Day-of-week range
- 0–6, Sun=0 (GitHub's docs show numeric only; prefer it)
- Seconds
- Not supported
- Year
- Not supported
- Special chars
- Exactly four documented: * , - / — no @hourly/@daily nicknames, no ? L W #
- Timezone
- UTC by default; optional `timezone:` field (IANA name) per cron entry, since March 2026
- Minimum interval
- 5 minutes (not 1 minute!)
- Reliability
- Scheduled runs may be delayed during high GitHub load
Examples
| Expression | Description |
|---|---|
*/5 * * * * | Every 5 minutes (the fastest allowed) |
0 * * * * | Every hour, on the hour |
0 0 * * * | Daily at midnight UTC |
0 9 * * 1-5 | Weekdays at 9 AM UTC |
0 0 1 * * | First day of every month at midnight UTC |
0 0 * * 0 | Weekly on Sunday at midnight UTC |
Gotchas
- **Minimum interval is 5 minutes**, not 1. `* * * * *` is *valid* POSIX cron and the workflow file commits and validates cleanly — it simply will not run every minute. GitHub documents only that "the shortest interval you can run scheduled workflows is once every 5 minutes"; it does not document rejecting or coercing shorter expressions. The fastest schedule that behaves as written is `*/5 * * * *`.
- **Defaults to UTC, but timezones are now supported.** Since March 2026 you can add a `timezone:` field (an IANA name like `America/Los_Angeles`) next to each `cron:` entry, and GitHub handles DST for you. Older guides that say "GitHub Actions is UTC-only, offset the hour manually" predate this — you no longer need the two-entry PST/PDT workaround.
- **No shortcuts.** `@hourly`, `@daily`, etc. are NOT supported. Write the full expression every time.
- **Delayed under high load.** GitHub's docs explicitly note that scheduled workflows may be delayed — sometimes by 30+ minutes — when the platform is busy. If you need precise timing, use a different scheduler.
- **Public-repository workflows get disabled when inactive.** GitHub's rule is "In a public repository, scheduled workflows are automatically disabled when no repository activity has occurred in 60 days." The *public repository* qualifier is usually dropped when this is repeated — it is not documented as applying to private repositories. On a public repo, push at least once every 60 days or re-enable via the UI or `gh workflow enable`.
- **Multiple schedules allowed.** You can list several `cron` entries under `on.schedule` to fire on multiple schedules. Use `github.event.schedule` to detect which one triggered the run.
Used by
- GitHub Actions workflows (`on.schedule.cron`)
- GitHub Actions reusable workflows triggered on schedule
- Scheduled GitHub Pages deployments via Actions
GitHub Actions cron is just standard Unix cron with two important constraints — 5-minute minimum interval and “may be delayed under load.” For most workflows (nightly builds, weekly health checks, daily report generation) this is perfectly fine. For anything time-sensitive, use a more reliable scheduler.
If a schedule is already written and simply is not firing, the cause is usually not the expression — it is the default-branch rule, the 60-day inactive-repo disabling, or an undocumented DST fall-back. Those are worked through in GitHub Actions schedule traps and fixes.