← Back to articles

CI/CD · Execution Limits

GitHub Actions Timeouts: Bound the Job and Its Riskiest Steps

Set explicit job and step timeouts, choose budgets from healthy runs and treat cancellation as an interruption to handle.

A cyan timer ring encloses a blue CI pipeline with a smaller amber step timer and stop gate.
Use an overall job budget and a narrower boundary for individual steps.

A CI job that waits indefinitely for a stuck command delays useful feedback. GitHub Actions provides two timeout boundaries: one for the job and another for an individual step.

Set the outer budget

Add timeout-minutes under a job to bound how long GitHub lets it run before cancellation. Choose a value from observed healthy runs, with room for normal variation. The following fragment illustrates the placement; it assumes checkout, Python setup and dependency installation steps are added before the test step:

jobs:
  verify:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - name: Run tests
        timeout-minutes: 10
        run: python -m pytest

The numbers are examples, not measured targets for your repository.

Bound risky steps separately

A step timeout limits how long that step runs before its process is killed. It does not extend the job's overall budget. GitHub requires a positive integer for step timeout-minutes, so use whole minutes in the workflow configuration.

Keep diagnostic context

Give steps specific names and emit useful progress before expensive operations. When a timeout occurs, investigate the last completed operation instead of automatically increasing every limit. A blocked network call, deadlock and legitimately slower test suite need different fixes.

Treat cancellation as interruption

For deployment work, design commands so an interrupted run has a clear recovery path. A CI timeout does not itself roll back changes made to an external service. Validate the interruption behavior before relying on the workflow to enforce an operational deadline.