Exact-minute GitHub Actions cron on the free tier
Scheduled workflows drift, jobs bill whole minutes, and daylight saving moves your clock. The lane JMM built to collect official numbers minutes after release.
GitHub Actions cannot promise an exact minute: the schedule event is best effort, and GitHub names the start of every hour as a high-load time. You can get close by scheduling an off-peak minute, pinning the clock with the schedule timezone field or spelling it as explicit UTC crons, and putting a one-minute gate job in front of the expensive work. JMM’s lane is built to start collecting official BLS numbers about five minutes after their 8:30 AM Eastern releases; its first scheduled window opens September 1, 2026, inside the free tier’s 2,000 monthly minutes for private repositories.
What a schedule actually promises
The schedule trigger is not a real-time clock. GitHub documents that scheduled workflows can be delayed during periods of high load, and it names the start of every hour as a high-load time. Scheduling at an odd minute such as :35 steps out of the busiest window, and choosing it costs nothing.
Two more platform facts shape the design. A schedule may carry an IANA timezone field for timezone-aware scheduling; without one, cron expressions are read in UTC. And in a public repository, GitHub disables scheduled workflows automatically after 60 days without repository activity, which matters for any project that expects its collector to outlive its commit cadence.
If a job truly cannot tolerate minutes of drift, a GitHub cron is the wrong tool and an external trigger is the right one. If a few minutes of drift is acceptable, which is true for capturing a document that stays online after publication, the rest of this page is the pattern.
Daylight saving: a timezone field, or crons spelled in UTC
JMM’s target clock is 8:35 AM Eastern, five minutes after the U.S. Bureau of Labor Statistics publishes its 8:30 AM releases. The one-line answer is the schedule timezone field, which lets a single cron follow Eastern time through daylight saving. JMM spells the clock out as two UTC crons instead: the field is a newer addition to the platform, a lane that feeds a publication pipeline earns its simplicity later, once the behavior it depends on has a longer public record, and explicit UTC instants mean the workflow file itself says exactly when it fires, with nothing resolved at run time.
Eastern time is UTC minus four in summer and UTC minus five in winter, so one local clock is two UTC times across the year. The workflow declares both, and on any given morning exactly one of them is 8:35 Eastern. The wrong one is not a problem to prevent but a run to end quickly: a gate job checks the checked-in release calendar for a supported release scheduled within 35 minutes of now, and the cron firing an hour off from every release instant never finds one. The same gate handles every non-release morning for free.
| Cron expression | Eastern reading in summer (EDT) | Eastern reading in winter (EST) |
|---|---|---|
| 35 12 * * 1-5 | 8:35 AM, the release minute | 7:35 AM, gate exits |
| 35 13 * * 1-5 | 9:35 AM, gate exits | 8:35 AM, the release minute |
The gate job and per-minute rounding
GitHub bills Actions per job, rounding each job’s minutes up to the nearest whole minute. That rounding is what makes a gate job the unit of economy: a job that checks a condition and exits costs one minute whether it ran for four seconds or fifty. The design rule that follows is to make the gate answer its question from data already in the repository, never from the network, so its runtime stays inside that first minute.
JMM’s gate reads a release calendar the engine’s other refresh lanes already committed. The expensive refresh runs only when the gate finds a release whose receipt the parsers can actually settle, one of exactly three: the Employment Situation, the Consumer Price Index, or the Producer Price Index, scheduled within the window. Everything else is a one-minute exit.
- Fire the schedule at an off-peak minute, never :00.
- Pin the clock with the schedule timezone field, or declare one cron per UTC offset when the instants should be explicit in the file.
- Gate on data already committed to the repository, not on a fetch.
- Let the wrong-offset firing and the quiet mornings exit inside one billed minute.
- Reserve the long job for the mornings the gate can name a reason to run.
The month’s arithmetic at zero dollars
GitHub’s free plan includes 2,000 Actions minutes a month for private repositories, and standard-runner minutes in public repositories are free. The lane’s design arithmetic, stated as design rather than as a measured record until it has a month of runs behind it: two gate firings per weekday at one minute each is roughly 42 minutes across a month, and a full collect-validate-build-push run on the roughly three receipt-eligible release mornings a month is about 25 minutes each. That totals near 120 minutes, about 6% of the included allowance.
One constraint is worth stating because it is the kind a zero-dollar pipeline actually has: the schedule went in while the month’s allowance was nearly exhausted, so the gate refuses every date before September 1, 2026, the next allowance reset. Until then the lane has never fired on its own clock, and every receipt on the site so far came from dispatched runs and hand-verified captures. A budget that exists is a budget the workflow file should be able to read.
When cron is the wrong tool
An external scheduler calling the repository dispatch API can hit a tighter window and can retry on its own terms, at the cost of a second system to run, secure, and pay for. A human dispatching the workflow on release mornings is more precise than any of this and does not scale past one human. JMM’s constraint is standing infrastructure at zero dollars with no second system, which is exactly the case the two-cron gate pattern is for.
Get the Pro launch email
This guide stays free. Join the list for one email when the forecast feed, machine-readable research files, alerts, and saved research workflows open.