Anatomy of a CI/CD Pipeline
A CI/CD pipeline is the automated assembly line that takes a code change from a developer's commit to a running artifact in production. While specific tools structure this differently — GitHub Actions calls the top-level unit a 'workflow' made of 'jobs' and 'steps', GitLab CI calls it a 'pipeline' made of 'stages' and 'jobs', Jenkins calls it a 'pipeline' made of 'stages' and 'steps' — the conceptual anatomy is remarkably consistent across tools. Understanding the generic shape of a pipeline makes it much easier to pick up any specific tool's syntax, because you're learning where a concept lives rather than learning the concept itself for the first time.
Cricket analogy: Whether it's the IPL, the Ashes, or a domestic Ranji Trophy match, every cricket contest still has the same skeleton of innings, overs, and deliveries; once you know that shape, switching from watching Bumrah bowl in the IPL to following a Test match at Lord's is just learning new names for the same structure.
The Source Stage
Every pipeline begins by reacting to a trigger — most commonly a push to a branch or the opening/updating of a pull request — and checking out the exact commit that triggered it. This stage also typically resolves which pipeline configuration applies, since many tools allow different behavior for different branches or paths (a technique called path filtering, useful in monorepos to avoid rebuilding unrelated services).
Cricket analogy: A match only gets underway once the umpire signals play and the toss decides who bats first, much like a pipeline waits for a specific trigger — a push or a pull request — before it decides which set of rules, like a day-night pink-ball format, actually applies.
The Build Stage
The build stage compiles or transpiles source code, resolves and installs dependencies, and produces a build artifact — this might be a compiled binary, a bundled JavaScript application, a container image, or a packaged library. A well-designed build stage is deterministic: given the same commit and the same dependency lockfile, it produces a bit-for-bit reproducible artifact, which matters enormously for debugging and for trusting that what was tested is what gets deployed.
Cricket analogy: A bat maker at Kashmir Willow takes raw wood, shapes it to exact spec, and produces an identical-grade bat every time from the same batch of willow, the way a deterministic build stage turns the same commit and lockfile into a bit-for-bit identical artifact.
The Test Stage
Tests typically run in a pyramid: fast unit tests first (seconds), then integration tests against real or containerized dependencies (minutes), then slower end-to-end tests (potentially many minutes). Pipelines often 'fail fast' by ordering stages so that cheap, high-signal checks (linting, unit tests) run before expensive ones (E2E tests), so a broken pipeline reports failure as quickly as possible rather than burning ten minutes of compute before reporting a typo.
Cricket analogy: A batsman's coaching starts with shadow practice against no bowler, then throwdowns from a coach, then finally a full net session against real bowlers, mirroring the test pyramid's climb from instant unit tests to slower end-to-end checks.
stages:
- build
- test
- package
- deploy
build-job:
stage: build
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
unit-tests:
stage: test
script:
- npm run test:unit
integration-tests:
stage: test
script:
- npm run test:integration
package-image:
stage: package
script:
- docker build -t registry.example.com/app:$CI_COMMIT_SHA .
- docker push registry.example.com/app:$CI_COMMIT_SHA
deploy-staging:
stage: deploy
script:
- ./deploy.sh staging $CI_COMMIT_SHA
environment: stagingThe Package and Deploy Stages
Packaging wraps the build artifact into a deployable unit — most commonly a versioned container image pushed to a registry, tagged with something traceable like the commit SHA. Deploy stages then take that specific, immutable artifact and place it into an environment, whether that's a staging environment for further validation or production itself. Good pipelines never rebuild the artifact between staging and production; the exact same tested binary or image is promoted forward, a principle sometimes called 'build once, deploy many'.
Cricket analogy: A single match ball, sealed and stamped with a serial number by the manufacturer, is the exact same ball used from the toss through to the final over — nobody swaps it between innings — mirroring how the same tagged artifact is promoted from staging to production without being rebuilt.
Think of a pipeline as a series of increasingly expensive filters, like a funnel sorting rocks by size. The cheapest, fastest checks (syntax/lint) sit at the top and reject obviously bad input immediately; only what survives reaches the slow, expensive checks (full E2E suites, security scans) further down.
A frequent anti-pattern is rebuilding the artifact separately for each environment (dev, staging, prod) instead of building once and promoting the same artifact forward. This breaks the guarantee that what was tested is exactly what gets deployed, since a rebuild can pull in different dependency versions or use different build flags.
- A pipeline's generic anatomy is: source/trigger, build, test, package, deploy — regardless of which specific tool implements it.
- Build artifacts should be deterministic and reproducible from the same commit and lockfile.
- Tests should run cheapest-and-fastest first to fail fast and save compute time.
- 'Build once, deploy many' means the same artifact is promoted through environments rather than rebuilt for each one.
- Path filtering lets monorepo pipelines skip stages unrelated to the changed files.
- Every tool's terminology (workflow/job/step vs. pipeline/stage/job) maps onto this same underlying structure.
Practice what you learned
1. What is the generic order of stages common to nearly all CI/CD pipelines?
2. What does the principle 'build once, deploy many' mean?
3. Why should fast, cheap tests like linting and unit tests run before slow tests like end-to-end suites?
4. What problem does rebuilding an artifact separately for staging and production (instead of promoting one build) risk introducing?
5. What is 'path filtering' used for in a monorepo CI/CD pipeline?
Was this page helpful?
You May Also Like
What Is Continuous Integration?
Continuous Integration is the practice of merging code changes into a shared branch frequently, with every merge automatically built and tested to catch integration problems early.
The CI/CD Tooling Landscape
A survey of the major CI/CD platforms — GitHub Actions, GitLab CI, Jenkins, CircleCI, and Azure Pipelines — and how their hosting model, configuration approach, and ecosystem differ.
Designing Multi-Stage Pipelines
Learn how to structure a CI/CD pipeline into logical stages — build, test, package, deploy — so failures surface early and each stage has a clear contract with the next.
Caching and Build Artifacts
Learn how CI/CD pipelines speed up builds with dependency caching and pass data between jobs using artifacts, and where each technique fits.
Related Reading
Related Study Notes in DevOps
Browse all study notesNginx Study Notes
DevOps · 30 topics
DevOpsAnsible Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsAdvanced Bash Scripting Study Notes
Bash · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics