CodeOath
← All posts
CI/CD & DevOps60 min total · 17 parts

CI/CD Pipelines Explained: From git push to Production

Contents — Part 7 of 17: Jobs, Steps, and Runners
Part 7 of 17 · ~1 min

Jobs, Steps, and Runners

Each job in a workflow runs on a fresh, isolated runner — a clean virtual machine or container spun up specifically for that job and destroyed afterward. This isolation is deliberate: it guarantees a build never accidentally depends on leftover state from a previous run (a stale file, a cached environment variable, a process still listening on a port) that wouldn't be there on a truly clean checkout.

That isolation has a real cost, though — nothing persists between jobs (or between separate runs) by default. A file one job writes to its own runner's disk is invisible to a different job's runner, since they're different machines entirely. Two mechanisms bridge this:

  • Artifacts — explicitly upload a file from one job, explicitly download it in another (as in the pipeline above). This is how a build's output gets from the build-and-test job to the deploy job without rebuilding it.
  • Caching — explicitly save and restore a directory (like node_modules or a compiler's cache) keyed by something like a lockfile hash, purely as a speed optimization (see below) — unlike an artifact, a cache is best-effort and a cache miss should never break the build, just slow it down.

Jobs within one workflow run in parallel by default unless a needs: relationship says otherwise — which is why the dependency graph (mentioned above) matters: declaring needs only where a real dependency exists is what lets independent jobs (lint, unit tests, a security scan) run concurrently instead of needlessly waiting on each other.