5 free GitHub Actions cost patterns

The first 5 patterns from the Cut Your CI Bill cookbook. Paste-ready, MIT-licensed.

These are the highest-impact patterns. If you apply only these five, a typical PR-heavy repo's monthly Actions bill drops by roughly half. No tools required to apply them - they are YAML edits.

Audit a workflow
Find which of these patterns are missing in your YAML.
Price a workflow
See the dollar number before and after applying these.

1. Cancel superseded runs with concurrency

Why Without a concurrency block, a fast push-to-push-to-push streak runs CI three times for the same final state. On a busy repo with 50 pushes/day this is the single biggest leak.

Apply Top of every workflow that runs on push or pull_request:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

Catch For deploy workflows you usually want cancel-in-progress: false so a deploy in progress finishes; concurrency just queues the next one.

2. Use ubuntu-latest unless you genuinely need macOS or Windows

Why macos-latest runs 10x the cost. windows-latest 2x. A test job that "happens to be" on macOS doubles or worse the bill of every PR.

Apply Audit runs-on: lines. macOS is required only when you build or sign Apple binaries (xcodebuild, codesign, notarytool). Windows is required only for native Windows code paths.

Catch Cross-platform tests should still exist. Move them to a nightly schedule or a workflow_dispatch job rather than running every PR.

3. Cache language tooling

Why Without cache:, setup-node, setup-python, setup-java, setup-go, and setup-dotnet re-download dependencies on every run. 30 to 90 seconds per job, sometimes more.

Apply

- uses: actions/setup-node@v4
  with:
    node-version: 20
    cache: npm

- uses: actions/setup-python@v5
  with:
    python-version: '3.12'
    cache: pip

Catch Cache keys depend on lockfiles. If the lockfile path is non-standard, set cache-dependency-path.

4. Set timeout-minutes on every job

Why The default is 360 minutes (6 hours). A hung step burns six hours of paid runner time before GitHub kills it.

Apply On every job:

jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 15

Catch Tune per job. Long-running builds deserve more headroom; tests deserve less.

5. paths: filters on heavy workflows

Why A 20-minute integration suite has no business running when a PR only touched the README.

Apply

on:
  pull_request:
    paths:
      - 'src/**'
      - 'tests/**'
      - 'package.json'
      - 'package-lock.json'

Catch Branch-protection rules that require this workflow won't see a status if it skips. Use paths-ignore to skip the workflow entirely, or keep a "always run" stub job that posts a green status when the heavy job isn't needed.

Auto-apply patterns 1, 4 (and others)

Patterns 1 and 4 above (concurrency and timeouts) are two of the four that ci-doctor --fix applies for you, in place. Free, MIT, no signup.

npx ci-doctor --fix --dry-run     # preview the patches
npx ci-doctor --fix               # apply

Get the other 25 patterns

The full Cut Your CI Bill cookbook

30 patterns total - cost, speed, security, maintenance - plus 5 paste-ready hardened workflow templates (CI, release, security scan, nightly, deploy). All MIT-licensed templates, lifetime updates. $19, one-time.

The cookbook covers what the patterns above stop short of: matrix sizing, artifact retention strategy, draft-PR skipping, OIDC for cloud auth, reusable workflows, dependabot grouping, and the security patterns (least-privilege permissions, SHA pinning, untrusted-input handling).

Get the cookbook

See also