keepcalculator

06 Numbers and Powers

GitHub Actions Cron vs External Scheduler: Which to Use?

Card No. 06·62340 · Updated · Standard formula, shown below

For scheduled tasks in a GitHub repository, you should use GitHub Actions cron for simple, repository-scoped jobs, and an external scheduler (like cron on a server or a managed service) when you need reliability, complex scheduling, or tasks that must run even if GitHub is down. This article compares both approaches so you can choose the right one for your project.

Background: What Is GitHub Actions Cron?

GitHub Actions is a CI/CD platform built into GitHub. It lets you define workflows in YAML files that respond to events like pushes, pull requests, or—importantly—a schedule. The schedule event uses cron syntax to trigger a workflow at specific times. For example, a workflow that runs every day at 3:30 AM UTC looks like this:

on:
  schedule:
    - cron: '30 3 * * *'

This is the simplest way to run a recurring job without leaving GitHub. You commit the workflow file, and GitHub handles the rest. The cron syntax follows the standard five-field format (minute, hour, day of month, month, day of week), with UTC as the timezone.

How GitHub Actions Cron Works

When you push a workflow with a schedule event, GitHub’s scheduler checks it and queues a workflow run at the specified times. The actual execution happens on GitHub-hosted runners (or self-hosted runners you provide). You can see the runs in the Actions tab, and you get logs, notifications, and a history of every execution.

Key technical details:

  • Cron expressions are evaluated in UTC. If you need a specific local timezone, you must convert it yourself.
  • The minimum interval is 5 minutes (e.g., */5 * * * *). You cannot schedule more frequently.
  • GitHub may delay or skip scheduled runs if the service is under heavy load. They do not guarantee exact execution times.
  • If a scheduled run is delayed by more than 45 minutes, it is dropped entirely.
  • There is no built-in retry for failed scheduled runs. If the workflow fails, you must re-run it manually or add logic to handle failures.

For many use cases—like sending a daily digest, updating a badge, or running tests at night—this is perfectly adequate.

What Is an External Scheduler?

An external scheduler is any system outside GitHub that triggers your jobs. Common options:

  • cron on a VPS: A traditional Unix cron job on a server you control. You can use curl to hit a webhook or git pull and run scripts.
  • Managed schedulers: Services like AWS CloudWatch Events, Google Cloud Scheduler, or Azure Scheduler can send HTTP requests to a GitHub Actions workflow via the repository_dispatch event.
  • CI/CD external triggers: Some tools (e.g., Jenkins, GitLab CI) have their own schedulers that can trigger GitHub Actions via webhooks.

With an external scheduler, you control the timing, retries, and failure handling. You are not dependent on GitHub’s internal scheduler, which is a black box. The tradeoff is that you must maintain and monitor the external system.

Comparing Reliability and Precision

The biggest difference is reliability. GitHub Actions cron is best-effort. According to GitHub’s documentation, scheduled workflows may be delayed or skipped during peak usage times. If your task must run exactly at a specific time—say, a financial report at market close—GitHub Actions is not the right choice.

External schedulers give you precise control. A traditional cron on a server runs at the exact second you specify (within the OS’s scheduling precision). Managed cloud schedulers also have high precision and often provide retry policies. For example, you can configure a retry if the webhook fails.

Another reliability factor: if GitHub is down, your scheduled workflows won’t run. An external scheduler can still fire, but if the job itself depends on GitHub (e.g., it’s a workflow that runs on GitHub), you’re still stuck. If the job is a script on your own server, it will run regardless.

How to Choose: Factors to Consider

  1. Frequency: If you need runs more often than every 5 minutes, GitHub Actions is out. Use an external scheduler.
  2. Precision: If the exact second matters, use an external scheduler. GitHub Actions can be delayed by minutes.
  3. Complexity: For simple daily or hourly jobs, GitHub Actions is easier—no extra infrastructure. For complex schedules (e.g., cron with timezone conversions, multiple triggers), an external scheduler may be simpler.
  4. Dependencies: If the job needs secrets from GitHub or runs on GitHub-hosted runners, keeping it in GitHub Actions is convenient. If it needs to run on your own infrastructure, an external scheduler might be better.
  5. Monitoring: GitHub Actions gives you built-in logs and run history. External schedulers require you to set up your own monitoring.
  6. Cost: GitHub Actions is free for public repositories and includes free minutes for private ones (2,000 minutes/month for free accounts). External schedulers may cost money (e.g., cloud services) or require you to maintain a server.

In short: use GitHub Actions cron for most repository maintenance tasks. Use an external scheduler when you need guaranteed execution, high frequency, or precise timing.

Common Problems and Misconceptions

Misconception: “Cron runs at the exact time I set.” Not true. GitHub explicitly states that scheduled workflows can be delayed. Many users report delays of several minutes during busy periods.

Misconception: “I can use any cron expression.” GitHub Actions supports the standard five-field cron, but not all features. For example, you cannot use @daily or @hourly shortcuts. You must write out the full expression.

Common problem: Timezone confusion. Since cron is in UTC, a job scheduled for 9 AM local time may run at a different hour if you forget to convert. Always double-check with a cron calculator.

Common problem: Skipped runs. If your repository is inactive (no pushes for 60 days), GitHub may disable scheduled workflows. You need to re-enable them manually.

Common problem: No retries. If a scheduled run fails due to a transient error (e.g., a flaky API), it won’t retry automatically. You must add retry logic in your workflow or use an external scheduler with retry policies.

Cost and Maintenance Comparison

GitHub Actions cron costs nothing extra beyond your normal GitHub usage. For public repositories, it’s free. For private ones, it consumes your included minutes. If you exceed the free tier, you pay per minute. For a simple scheduled job that runs once a day and takes a few minutes, the cost is negligible.

External schedulers have variable costs:

  • VPS cron: You pay for the server (e.g., $5/month for a basic VPS). You also handle updates, security, and uptime.
  • Cloud schedulers: Most have a free tier. For example, Google Cloud Scheduler allows 3 jobs per month for free, then charges per job. AWS CloudWatch Events charges per rule per month. Costs are usually low for a few jobs.
  • Maintenance: External schedulers require you to set up authentication (e.g., a personal access token for repository_dispatch), monitor failures, and keep the scheduler running.

For a hobby project, GitHub Actions is the clear winner. For a business-critical pipeline, the extra cost of an external scheduler is justified.

Alternatives and Hybrid Approaches

You don’t have to choose one exclusively. A common hybrid pattern:

  • Use an external scheduler (e.g., cron on a free tier of a cloud service) to send a repository_dispatch event to GitHub Actions. This gives you the reliability of the external scheduler and the convenience of GitHub Actions for execution.
  • Use GitHub Actions cron for non-critical tasks, and an external scheduler for the critical ones.

Another alternative is to use a self-hosted runner with its own cron. You can set up a cron job on the runner machine that triggers the workflow locally, bypassing GitHub’s scheduler. However, this requires maintaining the runner and the cron.

For tasks that don’t need GitHub at all—like a script that updates a database—you might skip GitHub Actions entirely and just run a cron job on a server.

Frequently Asked Questions

Can I use a timezone other than UTC in GitHub Actions cron?

No. The cron expression is always evaluated in UTC. You must convert your desired time to UTC yourself. For example, if you want 9 AM New York time (EST, UTC-5), you’d use 0 14 * * * (9 AM + 5 hours). Remember that daylight saving time shifts this, so you may need to adjust twice a year.

What happens if my scheduled workflow is delayed and then skipped?

GitHub will skip it if the delay exceeds 45 minutes. You won’t get a notification; it just won’t run. You can check the Actions tab to see if a run was skipped, but there’s no built-in alert. If you need to know, set up an external health check.

Can I run a GitHub Actions workflow more often than every 5 minutes?

No. The minimum interval is 5 minutes. If you need more frequent runs, you must use an external scheduler that triggers the workflow via repository_dispatch or a webhook. However, note that GitHub has rate limits on API calls, so you can’t trigger it every second.

Does a scheduled workflow run if the repository is archived?

No. Archived repositories cannot run workflows. If you archive a repo, scheduled workflows are disabled. You’d need to unarchive to re-enable them.

How do I retry a failed scheduled run?

You can manually re-run a failed workflow from the Actions tab. For automatic retries, you need to add logic in your workflow (e.g., a loop with a sleep) or use an external scheduler that retries webhooks. GitHub Actions does not have built-in retry for scheduled runs.

Is there a limit on the number of scheduled workflows?

No explicit limit on the number of workflows, but there are overall limits on API requests and concurrent jobs. For most users, this isn’t a concern. If you have hundreds of scheduled workflows, consider consolidating them into one workflow with multiple jobs.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →