How it works
The explanation, with examples you can run.
Stages and failing fast
Order checks by cost. Formatting, lint and type checks take seconds and catch a lot. Unit tests come next. Integration tests with real databases, image builds and end-to-end tests are slower, so they run after the cheap gates pass, or in parallel with them if they don't depend on each other.
lint ────────┐unit ────────┼──> e2e (needs the image) ──> publishbuild-image ─┘Think about the critical path: the longest chain of jobs that depend on each other. Parallel jobs are nearly free; shortening the critical path is what makes the pipeline faster.
Caching
Most pipeline time goes on downloading and compiling the same things again. Cache them:
- Package caches (npm, pip, Maven, Go modules) keyed on a hash of the lockfile, the OS and the tool version.
- Build caches (Docker layers, Gradle, Bazel, Turborepo) where the tool itself checks inputs.
A cache should only make things faster. If deleting it changes whether the build passes, something is wrong. And cache downloads, not secrets: a cache can be read by later runs, sometimes from other branches.
Artifacts: build once, promote
The output of the build stage is an artifact: a container image, a JAR, a tarball, a mobile build. Build it one time, from one commit, and give it an identity that can't change. For images that is the digest (sha256:...), not a tag like latest. Every later stage, staging tests and the production deploy alike, uses that same artifact.
Rebuilding per environment looks harmless but isn't. Between the staging build and the production build a base image tag can move or a dependency range can resolve to a new version. Then production runs code nobody tested. Configuration differs between environments; the artifact should not.
Keep the pipeline in the repository
The pipeline definition lives next to the code, is reviewed like code, and changes in the same pull request as the build it describes. Anyone should be able to run the same steps locally (make test, npm run ci) so the pipeline is a thin wrapper, not a second build system only the CI server understands.
When to stop and look
Track how long the pipeline takes and how often it fails for reasons unrelated to the change. If the median run creeps past fifteen minutes, or reruns become routine, fix that before adding more checks.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.