Skip to content
compiler.dev

GitHub Actions Time Limit, Timeouts and Delays

The GitHub Actions time limit is 6 hours per job on GitHub-hosted runners and 35 days per workflow run, and there are several other limits that look like slowness until you know them. This guide lists the documented limits (checked against GitHub's usage limits page on 2026-10-11), shows how to set shorter timeouts, and then covers the other half of the question: how to delay a job, a step or a whole workflow on purpose. It is related to the slow CI guide.

The limits that matter

LimitValue
Job execution time, GitHub-hosted runners6 hours; the job is terminated and fails
Workflow run time35 days; the run is cancelled (includes queue and approval time)
Job queue time, self-hosted runners24 hours, then cancelled
Matrix size256 jobs per workflow run
Workflow runs triggered500 per 10 seconds per repository
Approvals on environmentsA run may wait up to 30 days

Limits can change, so check GitHub's documentation on usage limits for current numbers. The practical one is the job limit: if a job nears 6 hours, you have a different problem, and sharding or a matrix is the answer.

Set shorter timeouts

The default timeout-minutes for a job is 360, which is the same 6 hours. A hung test then burns six hours of billed time. Set a timeout near twice your normal duration:

jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - run: npm ci
      - run: npm test
        timeout-minutes: 10   # steps can have their own timeout

A timeout fails the job cleanly and stops the bill. Pair it with concurrency to cancel superseded runs (speed-up guide). The workflow YAML checker can flag missing timeouts. If a job regularly hits its timeout, see GitHub Actions slow and slow e2e tests.

How to delay a step

The simplest delay is a shell command:

- name: Wait for deploy to settle
  run: sleep 60

This costs billed minutes, so use it sparingly. Better, wait for a condition instead of a fixed time, with a timeout:

- name: Wait for the service
  run: |
    for i in $(seq 1 30); do
      curl -fsS https://staging.example.com/health && exit 0
      sleep 10
    done
    exit 1

How to delay a job

Jobs start when their needs finish. To delay one, add a job that waits and make the next job depend on it. Two approaches that avoid paying for runner time while waiting:

  • Environment with a wait timer. In repository settings, create an environment (for example production) with a wait timer of up to 43,200 minutes (30 days) and optional required reviewers. A job that references it waits without using a runner:
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production   # wait timer and approvals configured in settings
    steps:
      - run: ./deploy.sh

Wait timers on environments are available for public repositories, and for private repositories on supported plans, so check your plan.

  • Concurrency groups to serialise runs rather than delay them: concurrency: group: deploy makes the next run wait for the current one.

How to delay a workflow

  • Schedule it. Run it at a future time with on: schedule. Schedules are UTC, and can be delayed under load, especially at the start of an hour; see cron schedules for the syntax and for "schedule not running" problems. The shortest interval is once every 5 minutes.
  • Dispatch later. Another workflow or an external scheduler can call workflow_dispatch through the API or gh workflow run at the time you choose.
  • Wait for another workflow. The workflow_run trigger starts a workflow when another one completes, which is a delay by dependency rather than by clock.

Unexpected delays that look like limits

  • Queued, not running: no free runner, or concurrency limit hit. Self-hosted jobs queue up to 24 hours.
  • Cron lateness: scheduled runs can start minutes late during high load.
  • Approvals: a run waiting for a reviewer counts toward the 35-day workflow limit.
  • Rate-limited actions: third-party APIs return 429 and your retry loop sleeps; set a total timeout.

If many jobs wait for runners, adding capacity or using faster runners cuts the time jobs hold slots. See faster GitHub Actions runners. compiler.dev was faster than GitHub's 2-core runner on 15 of 19 benchmarked stacks, by 1.1 to 3 times, and falls back automatically to your own runners.

Billing note

Delays that occupy a runner, like sleep, are billed as runner minutes at the rates in GitHub Actions pricing explained. Environment wait timers do not hold a runner.

FAQ

What is the GitHub Actions time limit?

6 hours per job on GitHub-hosted runners, and 35 days per workflow run. Set timeout-minutes lower to stop hung jobs early.

How do I delay a GitHub Actions job?

Use an environment with a wait timer, or make the job depend on an earlier job that waits. For short waits, sleep in a step works but uses billed minutes.

How do I delay a workflow?

Schedule it with on: schedule, trigger it later via workflow_dispatch, or chain it with workflow_run.

What happens when a job hits the limit?

The job is terminated and marked as failed. Cache or artifacts produced earlier remain.

Made by compiler.dev. Free tools · Pricing