A well-designed CI/CD pipeline has one job: get changes from a developer's machine to production safely and quickly. The median time from commit to production across high-performing teams is under 15 minutes. Most teams run 45-90 minutes. The gap is fixable.
The four stages every pipeline needs: lint/type-check (fail fast, under 2 minutes), unit tests (under 5 minutes, parallelized), integration tests (under 10 minutes, against real dependencies in Docker), and deploy. If any stage takes more than its target, it becomes a bottleneck that slows your entire release cycle.
Cache aggressively. GitHub Actions caches node_modules, pip packages, and Docker layers. A cold npm install on a Node.js project takes 90-180 seconds. A cached install takes 5-10 seconds. Add cache keys based on lockfile hash — if package-lock.json hasn't changed, restore the cache. This single change typically cuts pipeline time 40-60%.
Parallelize test suites. GitHub Actions matrix strategy runs multiple jobs in parallel. If your test suite has 1,000 tests that take 8 minutes sequentially, split them into 4 parallel jobs of 250 tests each — 2 minutes total. Jest, pytest, and RSpec all support sharding.
For GitHub Actions: use composite actions to deduplicate workflow YAML across repos. Use environments with protection rules for production deploys — require approvals for prod, auto-deploy to staging. Reusable workflows reduce the maintenance surface when you have 10+ repos.
Cost control: GitHub Actions charges per minute (free on public repos). macOS runners cost 10x Linux runners. Run Linux for everything except iOS/macOS-specific builds. Turn off cache for short-lived feature branches.