CI/CD is one of those acronyms that gets thrown around constantly. “We have CI/CD.” “The CI is failing.” “We need to set up a pipeline.”

But what does it actually do? And why should you care?

CI and CD are two separate things

CI — Continuous Integration

Every time code gets pushed or a PR is opened, an automated system:

  • Pulls the latest code
  • Installs dependencies
  • Runs type checks, linting, and tests
  • Builds the app

If any step fails, the PR is blocked from merging. This ensures the codebase always stays in a working state.

CD — Continuous Delivery / Deployment

After CI passes (and optionally after a merge to main), the system automatically deploys the new version to staging or production.

Together, they mean: merge to main, and it ships automatically.

What belongs in a pipeline?

Use the builder below to understand which steps matter and why:

CI/CD Pipeline Builder
75%Mostly solid

* Critical steps. Disabling them drops confidence regardless of score.  6/8 steps enabled.

Here’s what each step does and why it earns its place:

1. Install dependencies

- run: npm ci

npm ci (clean install) is stricter than npm install. It:

  • Installs exact versions from package-lock.json
  • Fails if the lockfile is out of sync with package.json
  • Never modifies package-lock.json

Always use npm ci in CI, never npm install.

2. Type check

- run: npx tsc --noEmit

Catch TypeScript errors that might not have been caught locally. This is cheap and fast — there’s no excuse to skip it.

3. Lint

- run: npx eslint .

Enforces code style, catches potential bugs (unused variables, missing await, etc.). Keeps the codebase consistent.

4. Unit tests

- run: npm test

Your business logic should be tested. CI is what makes tests actually matter — without it, tests are optional suggestions.

5. Build

- run: npm run build

Make sure the production build compiles without errors. Something might pass type checking but still fail to build.

6. Deploy

On a successful merge to main, trigger the deployment to production.

A basic GitHub Actions pipeline

GitHub Actions is the most common CI/CD tool for projects hosted on GitHub. Configuration lives in .github/workflows/.

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  ci:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"
          cache: "npm"

      - name: Install dependencies
        run: npm ci

      - name: Type check
        run: npx tsc --noEmit

      - name: Lint
        run: npx eslint .

      - name: Run tests
        run: npm test

      - name: Build
        run: npm run build

Commit this file, push it, and open a PR. GitHub automatically runs the workflow and shows a green/red check on the PR.

Branch protection: making CI mandatory

CI is useless if people can bypass it. In GitHub:

  1. Go to Settings → Branches → Add rule
  2. Set Branch name pattern: main
  3. Check Require status checks to pass before merging
  4. Select your CI job (ci) as required
  5. Check Require branches to be up to date

Now no one can merge a PR that fails CI. Your main branch is protected.

Adding auto-deploy

For a static site on Vercel, deployment is already automatic — Vercel watches your repo. But for more control, you can add a deploy step to your workflow:

      - name: Deploy to production
        if: github.ref == 'refs/heads/main'
        run: npx vercel --prod --token ${{ secrets.VERCEL_TOKEN }}
        env:
          VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
          VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

The if: github.ref == 'refs/heads/main' condition ensures this only runs on merges to main, not on every PR.

Why CI/CD matters beyond automation

CI/CD isn’t just about speed. It’s about confidence.

Without it:

  • Deployments are manual, scary events
  • “We can’t deploy on Fridays” becomes a rule
  • One bad commit can take down production for hours
  • Nobody wants to merge code late in the day

With it:

  • Merging is routine and low-risk
  • Bad code is caught before it reaches production
  • Deployment is boring and fast
  • The feedback loop from “write code” to “it’s in production” is minutes, not days

That shift — from deployment as a scary event to deployment as a normal, automatic thing — is what CI/CD is really about.