Chapter 2 · Lesson 2

Understanding the Pipeline Flow

Triggers, jobs, steps, and artifacts: the vocabulary that lets you read any pipeline file.

A pipeline is just a list of instructions that run automatically. Once you understand how it's structured — triggers, jobs, steps, artifacts — you can read any pipeline file in any CI tool.

The anatomy of a pipeline

A pipeline is a set of automated tasks triggered by an event — usually a code push. It's not magic; it's just a structured script running on a temporary server somewhere in the cloud.

Every pipeline has the same skeleton: something triggers it, jobs run (possibly in parallel), and each job contains sequential steps. Think of it like a recipe: the recipe is the workflow, a cooking stage is a job, and each individual instruction ("chop onions", "add salt") is a step.

😭 The manual pain

When you deploy manually, every developer follows a different mental checklist. One person runs tests before building; another forgets. One person sets environment variables correctly; another hard-codes a local path. The result is inconsistent deployments — "works on my machine" becomes your most common bug report.

✅ How CI/CD fixes it

A pipeline file is the single source of truth. Every run — on every machine, for every developer — follows exactly the same steps in exactly the same order. No more "I forgot to run the migration" because the pipeline runs it automatically, or fails loudly if it can't.

Pipeline anatomy: Workflow → Jobs → Steps

Let's zoom in on the structure. A workflow is the entire pipeline definition — it's usually a YAML file. Inside a workflow, you have jobs. Each job runs on its own fresh server. Inside each job, you have steps, which are individual commands that run one after another.

⚡ Trigger git push WORKFLOW (ci.yml) Job: test runs-on: ubuntu-latest Step 1: checkout code Step 2: npm install Step 3: npm test ↑ runs sequentially ↑ Job: deploy needs: test Step 1: checkout code Step 2: download artifact Step 3: deploy to server ↑ runs sequentially ↑
A workflow contains jobs. Jobs run on their own servers (possibly in parallel). Each job contains steps that run one after another. The "deploy" job uses needs: test to wait for the test job to pass first.

Jobs vs steps — what's the difference?

Steps run sequentially inside a single job on a single server. If step 2 fails, step 3 never runs. They share the same filesystem — so a file written in step 2 is still there in step 3.

Jobs can run in parallel (or in a defined order using needs). Each job gets a brand-new, empty server. A file written in one job is not automatically available in the next job. That's exactly why artifacts exist.

The pipeline lifecycle

When you push code, your pipeline doesn't instantly start running. It moves through these states:

  • Queued — the system received the trigger and is waiting for a free runner (the temporary server that actually runs your jobs).
  • Running — a runner has been assigned and your jobs are executing.
  • Passed (green) — all jobs completed successfully. Code is eligible for deployment.
  • Failed (red) — at least one job or step returned an error. The pipeline stops and notifies you.
  • Cancelled — someone manually cancelled it, or a newer push cancelled an older in-progress run.

Artifacts — passing files between jobs

Here's a real problem: you build your app in one job (producing a dist/ folder), then you want to deploy that exact built output in a second job. But jobs run on separate servers, so the dist/ folder doesn't exist on the deploy server.

The solution is artifacts. An artifact is a file or folder you explicitly save at the end of one job and download at the start of the next. Think of it like dropping a package in a shared locker — the build job puts the package in, and the deploy job picks it up.

Job: build npm run build → dist/ upload-artifact: dist/ 📦 Artifact Storage dist/ (zipped) upload Job: deploy download-artifact: dist/ deploy dist/ to server download
The build job produces a dist/ folder and uploads it as an artifact. The deploy job downloads that exact artifact — no manual copying, no inconsistency.

Environment variables

An environment variable is a named value passed to your pipeline at runtime, outside of the code. Instead of writing const dbUrl = "postgres://prod-server/mydb" in your code (which would expose it in your git history), you store it as an environment variable and reference it like process.env.DATABASE_URL.

In a pipeline, environment variables come from two places:

  • Workflow-level env — values you define directly in the YAML file, safe for non-sensitive configuration like NODE_ENV=production or a port number.
  • Secrets — sensitive values (API keys, passwords, tokens) stored encrypted in your CI platform and injected at runtime. You'll learn how to set these up in Section 3.

.github/workflows/ci.yml (snippet)

env:
  NODE_ENV: production          # safe to put in the file
  PORT: 3000                    # safe to put in the file
  # DATABASE_URL comes from a secret — NEVER hardcode it here

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Run tests
        run: npm test
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}   # injected securely
💡 Rule of thumb: env vars vs secrets

If you'd be comfortable pasting it in a public Slack message, it's probably fine in the YAML file. If it's a password, token, or key, it must live in secrets. When in doubt, use a secret — they're free and they're the right habit.

🎯 Mini challenge: build a paper pipeline

Grab a piece of paper (or open a text file). Design a pipeline for the Task Manager API with these requirements:

  • It runs whenever code is pushed.
  • It has two jobs: test and deploy.
  • The deploy job must not run if test fails.
  • Both jobs need the source code.

Write out the job names, what each step does, and where you'd upload/download an artifact if you needed to pass the build output. Then compare your sketch with the YAML you'll write in Section 2.

Lesson Summary
  • A pipeline is a workflow containing jobs containing steps — each level adds a layer of structure and control.
  • Steps run sequentially on the same server; jobs run on separate servers and can run in parallel.
  • The pipeline lifecycle: Queued → Running → Passed or Failed. A failed step stops the pipeline — code doesn't deploy.
  • Artifacts are the way jobs share files — one job uploads, the next downloads.
  • Environment variables inject configuration safely; secrets handle the sensitive ones so credentials never appear in source code.