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.
These are averaged timings from GitHub Actions across 200+ developer repositories, measured from job queue to completion. The distribution is consistent across project types:
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%.
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.
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.
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'
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.
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.
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."
Driftn's Deployments dashboard tracks your deploy history, failure rate and cycle time across Vercel and other platforms.
View the dashboard