A scheduled workflow runs at the cron time in UTC unless you set a timezone, from the latest commit on the default branch. It can start late, especially at the top of an hour, and in public repositories it is disabled after 60 days without activity. Do not treat the schedule as exact.
The rules in the documentation
GitHub's event reference lists the following for the schedule trigger:
- It uses POSIX cron syntax with five fields, and by default runs in UTC. You can optionally set an IANA timezone string.
- It runs on the latest commit on the default branch, and only there.
- The shortest interval is once every 5 minutes.
- Shortcuts such as
@dailyand@weeklyare not supported. - The event can be delayed during periods of high load. High load times include the start of every hour, and if load is high enough some queued jobs may be dropped. To lower the chance of delay, schedule at a less busy time, not on the hour.
- In a public repository, scheduled workflows are automatically disabled when no repository activity has occurred in 60 days.
- Notifications for a scheduled workflow go to the user who last modified the cron syntax, and that user also becomes the actor for the runs.
Choose a time that makes sense
A cron line like this runs a weekly report on Monday at 06:17 UTC, which avoids the top of the hour:
on:
schedule:
- cron: '17 6 * * 1'
Pick the hour for the people who read the output. If your team is in several time zones, a Monday morning report in one region is a Sunday evening one in another. When daylight saving is involved, the docs add a note about how a schedule landing in a skipped hour is advanced to the next valid time, so a 2:30 AM schedule would run at 3:00 AM on a spring forward day when a timezone is set.
What can go wrong
| Problem | Effect | Fix |
|---|---|---|
| Run delayed | Report arrives late | Do not tie deadlines to the minute |
| Job dropped under load | A run never happens | Add a freshness check, see below |
| Repo quiet for 60 days | Schedule disabled without a loud signal | A heartbeat alert, and a monthly activity commit if needed |
| Last editor leaves | Notifications go to someone who is gone | Re-save the cron line under a team owned account |
| Workflow lives on a non default branch | It never runs | Keep the file on the default branch |
The dropped job and the disabled schedule are the dangerous ones, because silence looks like a clean result. Build a check that asks the opposite question: when did the scan last succeed? Our guides on detecting a silently failing scheduled security scan and heartbeat alerts show how. Another useful companion is why a scheduled GitHub Actions scan stopped running.
Combine with event triggers
A schedule is the backstop, not the whole plan. Run scans on pull requests and merges so new code is checked straight away, and use the schedule to catch advisories published after code was merged. See scheduled or event driven scans.
Try it yourself
Click through it at your own pace, or open it full screen.
Notice that findings can appear between scans, which is the gap a schedule alone leaves.
Safeguard offers continuous monitoring so newly published advisories are matched to what you already ship. Try the free scan at gold.safeguard.sh/scan.
Quick check
Can I schedule a workflow from a feature branch?
No. Scheduled workflows run only on the default branch.
Is 00:00 a good time for a nightly scan?
It is a busy slot, so prefer an off minute such as 17 past a quiet hour.
Sources
Last reviewed: 19 October 2026.