---
name: optimise-github-actions-ci-costs
description: Audits existing GitHub Actions workflows for wasted minutes and money - measure recent runs, then pick the top three fixes from caching, cancel-in-progress concurrency, path filters, smaller matrices, duplicate workflows and parallel steps - without dropping required checks. Use when CI is slow or expensive, the user hits their Actions minutes limit, or wants a workflow cost audit.
license: MIT
metadata:
  category: deployment
  tags: "github-actions,ci,performance"
  author: johnny-bravo
  version: "1.0"
  updated: "2026-11-03"
  status: published
  aliases: "github actions efficiency, reduce ci minutes, ci cost, slow ci, actions billing, cancel in progress, workflow caching"
  source_url: "https://github.com/github/awesome-copilot/blob/61fa1fa8fcc63d6dbd2f07a75aeb8e214df5acfb/skills/github-actions-efficiency/SKILL.md"
  source_license: MIT
  copyright: "Copyright GitHub, Inc."
  original_author: "mutl3y (github/awesome-copilot, github-actions-efficiency)"
  modified: "Adapted by TheSkillVault on 2026-11-03: rewritten as a single self-contained audit with original YAML examples; the pointers to the upstream references/ files were dropped (those files are not included); added plain-language steps, gotchas and done-when. Not the original file."
  imported_on: "2026-11-03"
---

# Optimise GitHub Actions CI costs

CI that runs every job on every push burns minutes and makes people wait. Most of the waste comes from a few causes. This skill measures first, then applies only the fixes the evidence supports.

## When to use
- Your GitHub Actions runs are slow, or you hit the free minutes limit.
- Every push to a pull request queues another full run while old ones keep going.
- A docs-only change still runs the whole test matrix.

## When not to use
- You have no CI yet. Use configure-github-actions-ci first.
- A check is failing. Use fix-failing-ci-checks.

## Steps
1. Measure. Run `gh run list --limit 20` and open the slowest runs with `gh run view <run-id>`. Note which jobs take longest and how often each workflow runs. Without gh, paste the workflow files and say the result is static-only.
2. Scan the workflows: `rg -n "on:|concurrency:|paths:|cache:|matrix:" .github/workflows`.
3. List the waste you found, and pick at most three fixes, ranked by minutes saved per day (time saved per run x runs per day):
   - Dependency caching keyed on the lockfile (`actions/setup-node` with `cache: npm`, or `actions/cache`).
   - `concurrency` with `cancel-in-progress: true` on pull request workflows.
   - `paths` or `paths-ignore` filters so docs-only changes skip heavy jobs.
   - A smaller matrix on pull requests, and the full matrix on main or nightly.
   - Removing a workflow that runs the same checks as another.
   - Splitting one long serial job into parallel jobs on the critical path.
4. Check each fix against the guardrails below. Drop any that fails.
5. Apply the fixes in one small PR, with the before numbers in the description.
6. Prove it on a non-protected branch: push twice quickly to see the cancel, and push a docs-only change to see the skip.
7. After a week, compare minutes and wait time with the before numbers. Report total runner time and PR wait time separately.

## Example
```yaml
on:
  pull_request:
    paths-ignore: ["**.md", "docs/**"]
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22, cache: npm }
      - run: npm ci && npm test
```

## Guardrails
- Never skip release, migration, schema or shared-library checks to save minutes.
- Keep every matrix version or platform you promise to support.
- Do not cancel in-progress runs on main or release branches; a deploy could stop halfway.
- If a path-filtered workflow is a required check, a skipped run can block merging. Use a job-level filter or a small always-run job instead.
- Keep repo YAML changes separate from org or billing settings.

## Gotchas
- Never cache folders that hold secrets, tokens or `.env` files. Cache only dependencies and build output.
- Caches are per branch with fallback to the default branch. A cache key that never changes serves stale packages.
- Bot or formatter jobs that commit back can trigger loops. Make them opt-in with a label or manual trigger.

## Portability
These techniques work in any CI. If you use GitLab CI or another tool, use its equivalent: `interruptible` and `rules: changes` in GitLab, for example.

## Done when
- At most three fixes shipped, each backed by a measured waste source.
- Required checks still run where they must, and the cancel and skip were seen live.
- You have before and after numbers for runner minutes and PR wait time.

## Example prompt
"Our GitHub Actions bill is too high. Audit the workflows, show me where the minutes go, and propose the top three fixes without dropping any required checks."

---
Adapted from "github-actions-efficiency" in github/awesome-copilot (MIT, Copyright GitHub, Inc.). Original: https://github.com/github/awesome-copilot/blob/61fa1fa8fcc63d6dbd2f07a75aeb8e214df5acfb/skills/github-actions-efficiency/SKILL.md. See LICENSE.txt.
