Lesson 3 of 5

Pipelines & Stages

A pipeline is the assembly line a change rides from "pushed" to "deployable": an ordered series of stages, each a gate the change must pass. The concepts here are identical across every CI system — GitHub Actions, GitLab CI, Jenkins — only the YAML dialect changes.

💡 The Bottom Line

Order stages cheapest-first so failures are fast (fail fast). Build once, producing an artifact; every later stage — including production deploy — uses that exact artifact, never a rebuild. Within a stage, independent jobs run in parallel.

The classic shape

┌───────┐   ┌──────────┐   ┌──────────────┐   ┌─────────┐   ┌────────┐
│ Lint  │ → │  Build   │ → │     Test     │ → │ Staging │ → │  Prod  │
│ ~30s  │   │  ~2min   │   │ (parallel)   │   │ deploy  │   │ deploy │
└───────┘   └─artifact─┘   │ unit | e2e   │   └─────────┘   └────────┘
                           └──────────────┘

Why "build once" is a rule, not a preference

If staging tested build #1 and production runs a freshly-made build #2, you deployed something that was never tested — different dependency resolution that hour, different timestamp, different anything. The artifact is the thing you verified; promotion means moving that thing forward unchanged. This is also why Docker images make such good artifacts: the image tested in staging is bit-identical to the one production pulls (the Docker track's ":latest" warning is this same principle from the other side).

Environments as promotion rungs

Most teams run the artifact up a ladder: an integration environment (always tracking main), then staging (production-like, final rehearsal), then production — often with a manual approval gate before the last rung. Each rung raises confidence; the artifact never changes, only your certainty about it.

🙋 There Are No Dumb Questions

Q: Where do database migrations fit in a pipeline?
A: As a deploy-stage step, run against each environment right before (or as) the new version starts — and written to be backward compatible, so the old code still running during the rollout doesn't break (add a column, don't rename it mid-flight). Migrations are the classic example of why staging should mirror production: it's your rehearsal for exactly this step.

⚠️ Watch Out

Guard your pipeline's total runtime. Every added check is worth it in isolation, and the sum quietly grows until "push to green" takes 50 minutes and developers batch changes to avoid the wait — which un-does the small-merges habit from Lesson 2. Parallelize, cache dependencies, and treat pipeline speed as a feature with an owner.

🔧 Try It Yourself

Design your project's pipeline on paper — this exercise takes ten minutes and becomes your YAML file almost line-for-line later:

Stage 1 (seconds):  lint? typecheck? format check?
Stage 2 (minutes):  build → what exactly is my artifact?
Stage 3 (minutes):  which test groups can run in parallel?
Stage 4:            deploy where first? what proves it healthy?
Gates:              which arrow needs a human approval?

If you can't name the artifact, that's finding #1 — a pipeline that rebuilds at every stage has nothing verifiable flowing through it.

✅ Quick Check

Why should production deploy the exact artifact built earlier in the pipeline, rather than rebuilding?


Next up: the pipeline ends at "deploy" — but how you swap live traffic to new code is its own craft: rolling, blue-green, canary, and flags.

← Back to
Next →