DevOps

Why your CI/CD pipeline is slow and how to fix it

A 12-minute CI pipeline is a tax on every developer on your team. Every push, every PR, every hotfix — 12 minutes of waiting before you know if it worked. For a 5-person team running 20 pipeline executions per day, that's 20 hours of developer time lost every week to waiting for CI.

Most pipeline slowness comes from the same 4 or 5 causes, and most of them are fixable in an afternoon. Here's what the data shows.

Where time actually goes

These are averaged timings from GitHub Actions across 200+ developer repositories, measured from job queue to completion. The distribution is consistent across project types:

Average GitHub Actions pipeline time breakdown — Node.js/Python projects,
200+ repositories. Median total time: 8m 42s. Excludes queue wait (median: 22s).

Dependency installation is almost always the biggest chunk — and it's almost always cached poorly or not at all. The fix for that one issue alone cuts most pipelines by 40–60%.

1. Fix dependency caching (biggest win)

Every time a runner starts, it's a fresh VM. Without caching, it downloads and installs every dependency from scratch — even if nothing changed since the last run.

# Before: no caching (~3min for npm install)
- run: npm install

# After: cache node_modules by package-lock hash
- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: npm-${{ hashFiles('package-lock.json') }}
    restore-keys: npm-

- run: npm ci --prefer-offline

This alone reduces dependency time from 2–4 minutes to 10–30 seconds on cache hit. Cache hit rate is typically 85–95% on active repos.

2. Parallelize independent jobs

Most pipelines run everything sequentially: lint → test → build → deploy. But lint and unit tests are independent — they can run at the same time.

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test

  build:
    needs: [lint, test]  # only runs if both pass
    runs-on: ubuntu-latest
    steps:
      - run: npm run build

Lint and test now run in parallel. Total time is max(lint, test) + build, not lint + test + build. For typical projects this saves 2–4 minutes.

3. Skip CI when nothing relevant changed

If you push a commit that only changes docs or README, there's no reason to run tests. The paths filter in GitHub Actions handles this:

on:
  push:
    branches: [main]
    paths:
      - 'src/**'
      - 'package*.json'
      - '.github/workflows/**'
    paths-ignore:
      - 'docs/**'
      - '*.md'
      - 'LICENSE'

4. Use faster runners for the right jobs

GitHub's standard runners use 2-core machines. For CPU-intensive jobs (TypeScript compilation, test suites with many workers), 4-core or 8-core runners finish significantly faster. The cost is 2x or 4x, but if you're spending $200/month on Actions minutes and a 4-core runner cuts your time in half, you break even and save developer time.

Runner pricing (GitHub Actions, 2026)

Standard (2-core): $0.008/min. 4-core: $0.016/min. 8-core: $0.032/min. 16-core: $0.064/min. If a 2-core job takes 10 minutes, a 4-core runner that does it in 6 minutes costs the same total but finishes 4 minutes sooner.

Calculate what slow CI is costing your team

CI time cost calculator
How much developer time your current pipeline is consuming per year, and what you'd save by optimizing it.
Hours lost/week (current)
Hours saved/week
Hours saved/year

The 5-step fix in order

  1. Add dependency caching — 40–60% reduction for most projects
  2. Parallelize lint, test and type-check — saves max(removed jobs) minutes
  3. Add path filters — skip CI for docs/config-only changes
  4. Split large test suites — use matrix strategy to shard tests across runners
  5. Use larger runners for compilation — worth it for TypeScript-heavy projects

A pipeline that took 12 minutes consistently comes down to 3–4 minutes with these changes. That's not a marginal improvement — it changes the experience of development from "push and wait" to "push and check back in a moment."

Monitor your deployment frequency with Driftn

Driftn's Deployments dashboard tracks your deploy history, failure rate and cycle time across Vercel and other platforms.

View the dashboard