What a Good CI/CD Pipeline Actually Does
Not just "runs tests before deploy." A real pipeline:
- Validates code quality (lint, types, tests)
- Builds artifacts
- Deploys to staging automatically
- Gates production on approval or scheduled windows
- Rolls back automatically on failure
Here's how to build one with GitHub Actions.
The Base Pipeline
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Type check
run: npx tsc --noEmit
- name: Lint
run: npm run lint
- name: Test
run: npm test -- --coverage
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
Parallel Jobs
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'npm' }
- run: npm ci && npm run lint
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'npm' }
- run: npm ci && npx tsc --noEmit
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: testpass
POSTGRES_DB: testdb
options: >-
--health-cmd pg_isready
--health-interval 10s
env:
DATABASE_URL: postgresql://postgres:testpass@localhost:5432/testdb
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'npm' }
- run: npm ci
- run: npx prisma migrate deploy
- run: npm test
deploy-staging:
needs: [lint, typecheck, test] # runs after all pass
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./scripts/deploy.sh staging
env:
DEPLOY_KEY: ${{ secrets.STAGING_DEPLOY_KEY }}
Production Deployment with Approval
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production # requires approval in GitHub settings
steps:
- uses: actions/checkout@v4
- run: ./scripts/deploy.sh production
env:
DEPLOY_KEY: ${{ secrets.PROD_DEPLOY_KEY }}
In GitHub Settings → Environments → production, you can require reviewers before the job runs.
Caching Dependencies
- uses: actions/cache@v3
with:
path: |
~/.npm
${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
Proper caching cuts CI time by 40-60%.
Deploy Script Pattern
#!/bin/bash
# scripts/deploy.sh
set -euo pipefail
ENV=${1:-staging}
echo "Deploying to $ENV..."
# Build
npm run build
# Run migrations before deploying new code
if [ "$ENV" = "production" ]; then
npx prisma migrate deploy
fi
# Deploy (Vercel example)
vercel deploy --prod --token=$VERCEL_TOKEN
# Smoke test
sleep 10
curl -f https://app.example.com/api/health || {
echo "Health check failed, rolling back"
vercel rollback --token=$VERCEL_TOKEN
exit 1
}
echo "Deploy complete"
Slack Notifications
notify:
needs: deploy-production
if: always()
runs-on: ubuntu-latest
steps:
- name: Notify Slack
uses: slackapi/slack-github-action@v1.24.0
with:
payload: |
{
"text": "${{ needs.deploy-production.result == 'success' && '✅' || '❌' }} Production deploy ${{ needs.deploy-production.result }}",
"attachments": [{
"text": "${{ github.event.head_commit.message }}",
"footer": "by ${{ github.actor }}"
}]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
Secrets Management
# Never hardcode secrets
# Bad:
env:
API_KEY: sk-abc123
# Good:
env:
API_KEY: ${{ secrets.API_KEY }}
# Per-environment secrets
# GitHub Settings → Environments → staging/production
# Different values per environment, automatic scoping
The 10-Minute Goal
Pipeline phases and target times:
- Lint + typecheck: 2 min (parallel)
- Tests with DB: 3 min
- Build: 2 min
- Deploy: 1 min
- Smoke test: 30s
Anything over 10 minutes is friction that causes engineers to merge without waiting for CI.
Fast pipelines get used. Slow ones get bypassed.
GitHub Actions workflows for test, build, and deploy pre-configured: Whoff Agents AI SaaS Starter Kit includes CI/CD templates ready to drop in.
Top comments (0)