How CI/CD Works
The pipeline mental model — what runs when, why it matters, and how GitHub Actions fits in
CI/CD stands for Continuous Integration and Continuous Deployment. CI means every code change is automatically built and tested before it merges. CD means passing code is automatically deployed to production without manual steps. Together they form a pipeline that catches bugs before users do and ships code faster than any manual process can. For a Next.js SaaS like Launchpad, this means a broken migration or a missing environment variable is caught in the pipeline — not discovered by your first paying customer at 2am.
The three stages of a good pipeline
- Continuous Integration (CI) — Every push and pull request triggers automated tests. If tests fail, the PR cannot merge. This is the safety net that catches regressions before they reach production. For Launchpad: a failed Supabase migration type check is caught here, not in production.
- Continuous Delivery — After tests pass, the build artifact is created and staged for deployment. A human still approves the production deploy. Used when regulatory or business approval is required before each release.
- Continuous Deployment (CD) — After tests pass, code is automatically deployed to production with no human approval. Most indie SaaS products — including Launchpad — operate this way. Merge to main, it ships within 3 minutes.
GitHub Actions concepts
- Workflow — A YAML file in .github/workflows/ that defines what to do and when. A repo can have multiple workflows (one for CI, one for deployment, one for releases). Each is independent.
- Event (trigger) — What causes the workflow to run — push, pull_request, schedule, workflow_dispatch (manual button). You can filter by branch: only run on push to main, or on any PR targeting main.
- Job — A group of steps that run on a fresh virtual machine. Jobs run in parallel by default. Use `needs` to create dependencies between jobs — the deploy job must wait for the test job.
- Step — A single shell command or reusable action within a job. Steps run sequentially. If one step fails, subsequent steps are skipped (unless you use `continue-on-error`).
- Action — A reusable unit from GitHub Marketplace (actions/checkout, actions/setup-node) or your own repo. Actions hide complexity — `actions/checkout@v4` handles git authentication, sparse checkout, and submodule support in one step.
- Runner — The VM that executes the workflow. GitHub provides ubuntu-latest, windows-latest, macos-latest at no charge for public repos. Ubuntu is the default for web projects — it starts in under 10 seconds.
What breaks in production when you skip CI
- A missing environment variable silently makes API calls return 401 — The build succeeds locally because your .env.local has the key. CI catches it when you add env var checks to the build step.
- A TypeScript error that only appears with strict mode enabled on the server — Your editor may be configured differently from the CI tsc invocation. CI is the ground truth.
- A dependency with a broken postinstall script that only fails on Linux — Developers on Mac never see it. The Vercel deploy (Linux) fails 60 seconds after every merge until someone investigates.
- A database migration that passes locally but fails on the production schema — Integration tests that run against a real Supabase test project catch this. Unit tests alone do not.
Build the Launchpad CI workflow from scratch
Create the workflow directory
mkdir -p .github/workflowsWrite the initial ci.yml — triggers on any branch push so every developer gets feedback
name: CI
on:
push:
pull_request:
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
env:
NEXT_PUBLIC_SUPABASE_URL: placeholder
NEXT_PUBLIC_SUPABASE_ANON_KEY: placeholderCommit and push to trigger the workflow
git add .github/workflows/ci.yml
git commit -m "ci: add initial CI workflow for Launchpad"
git pushOpen the Actions tab on GitHub
Repository → Actions tab. You will see a workflow run appear within seconds. Click it to see the job, then click the job to see each step expanding in real time. Green checkmark = passed. Red X = failed — the failing step is highlighted with its full terminal output.
Introduce a deliberate build error to see the failure notification
// In any .tsx file, add a type error:
const x: string = 123 // Type error: number is not assignable to stringPush the error and observe the failure
git add -A
git commit -m "test: deliberate type error"
git pushGitHub sends an email notification when a workflow fails on a branch you pushed. The Actions tab shows the red X. The build step output shows the exact tsc error with file and line number. Revert and push again to restore green.
Revert the deliberate error
git revert HEAD
git push→ Workflow reruns automatically on the new push. You should see a new green run appear within 30 seconds.
Try this
Create the initial GitHub Actions workflow file `.github/workflows/ci.yml` for Launchpad. Configure it to trigger on push to any branch and run `npm ci && npm run build`. Push a change and watch it run in the Actions tab. Then introduce a deliberate build error — a syntax mistake or TypeScript type violation — and observe the failure notification email and the red X in the Actions tab. Screenshot the failing step output. Fix the error and push again to confirm the pipeline goes green. This is the foundation every subsequent lesson builds on.