CI/CDDevOpsAutomation

CI/CD Pipeline Best Practices

13 min read
A well-designed CI/CD pipeline is the foundation of high-performing engineering teams. It provides fast feedback on code quality, automates repetitive testing and deployment tasks, and gives teams the confidence to release frequently. This guide covers pipeline design principles, stage ordering, caching strategies, and security practices that work at any scale.

Pipeline Stage Design

A production-grade pipeline typically includes five stages: lint and format check, unit tests, build, integration/E2E tests, and deploy. Order these stages by speed and failure likelihood — fast checks that frequently catch issues should run first. A formatting check that takes 5 seconds and fails on 20% of commits should run before a 10-minute E2E test suite. This fail-fast approach minimizes the time developers wait for feedback.

.github/workflows/ci.yml
name: CI Pipeline
on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npm ci --prefer-offline
      - run: npm run lint
      - run: npm run typecheck

  test:
    needs: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npm ci --prefer-offline
      - run: npm test -- --coverage

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npm ci --prefer-offline
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: dist/

Caching for Speed

Pipeline speed directly affects developer productivity. The most impactful optimization is aggressive caching of dependencies, build artifacts, and Docker layers. Cache node_modules or the npm/pnpm cache directory between runs. For Docker builds, use multi-stage builds with layer caching enabled. Pin your cache keys to lockfile hashes so caches invalidate automatically when dependencies change.

tip

Use npm ci instead of npm install in CI pipelines. It's faster, deterministic (installs exactly what's in package-lock.json), and will fail if the lockfile is out of sync with package.json.

Branch Protection and Review Gates

Enforce branch protection rules on your main branch: require passing CI checks before merge, require at least one code review approval, prevent force pushes, and require branches to be up-to-date before merging. These rules ensure that every change merged to main has been tested and reviewed. For high-stakes deployments, consider adding a manual approval gate between staging and production.

  • Require status checks to pass before merging (all CI stages green)
  • Require at least one approved review from a code owner
  • Block force pushes to main/production branches
  • Require linear history (rebase before merge) to keep the commit graph clean

Secrets and Security in Pipelines

Never store secrets in code or pipeline configuration files. Use your CI provider's encrypted secrets store (GitHub Actions secrets, GitLab CI variables, etc.) and inject them as environment variables at runtime. Rotate secrets regularly. Audit access to pipeline secrets — limit them to the pipelines that actually need them. Scan for accidentally committed secrets using tools like gitleaks or truffleHog as a pre-commit hook and CI step.

warning

Pipeline logs can leak secrets through error messages, debug output, or environment dumps. Configure your CI provider to mask secret values in logs, and review pipeline output after adding new secrets.

Deployment Strategies

Choose a deployment strategy that matches your risk tolerance. Rolling deployments gradually replace old instances with new ones and are suitable for most applications. Blue-green deployments maintain two identical environments and switch traffic atomically — ideal when rollback speed is critical. Canary deployments route a small percentage of traffic to the new version first, monitoring for errors before full rollout. All strategies require health checks and automated rollback triggers.