Speeding Up Slow CI Pipelines in GitHub Actions

A
Author
08 May, 2026 1 min read 250 views

A CI pipeline that takes 25 minutes slows down every pull request. Most pipelines can be made several times faster with a few changes.

1. Cancel outdated runs

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

When you push again to the same branch, the previous run stops instead of finishing pointlessly.

2. Only run what changed

on:
  pull_request:
    paths:
      - 'api/**'
      - 'package-lock.json'
      - '.github/workflows/api.yml'

In a monorepo, separate workflows per app with path filters avoid testing the mobile app when only the docs changed. Be careful with required checks: a skipped workflow can block merging, so mark those checks as required only where they always run, or use a small "gate" job.

3. Run independent jobs in parallel

jobs:
  lint:      { runs-on: ubuntu-latest, steps: [...] }
  typecheck: { runs-on: ubuntu-latest, steps: [...] }
  unit:      { runs-on: ubuntu-latest, steps: [...] }
  e2e:
    needs: [unit]       # only what truly depends on something waits
    runs-on: ubuntu-latest

4. Cache everything you download

  • Package manager caches via setup-node, setup-python and friends.
  • Build tool caches (Next.js, Turborepo, Gradle, Cargo).
  • Docker layers with type=gha caching.

5. Split slow test suites

strategy:
  matrix: { shard: [1, 2, 3, 4] }
steps:
  - run: npx playwright test --shard=${{ matrix.shard }}/4

6. Bigger or faster runners

Larger GitHub-hosted runners (more CPU cores) can be cheaper overall if they halve the run time of CPU-bound builds.

Measure first

Look at step timings in a few recent runs. Often one step (a full reinstall, an unnecessary build, a slow E2E suite) is most of the time, and fixing it is the biggest win.

Was this article helpful?

Comments

No comments yet. Have a question or a tip? Be the first to share it.

Leave a comment

Comments are reviewed before they appear.