Skip to content
Latchkey

Jobs, Steps, and Runners Explained

Jobs, steps, and runners are the three nested units that decide what runs, in what order, and on which machine.

Jobs, steps, and runners are easy to confuse but behave very differently - especially around parallelism and isolation. This lesson nails down the distinctions so your workflows do what you expect.

Steps run in sequence

A step is the smallest unit: a single command or action. Steps inside a job run in order, top to bottom, on the same runner, sharing the same filesystem and environment. If a step fails, the remaining steps in that job are skipped by default. Steps are how you express "do this, then this, then this."

Jobs run in parallel

A job is a group of steps that runs on its own runner. Importantly, jobs in a workflow run in parallel by default, each on a separate, isolated machine. This is great for speed - you can lint, test, and build simultaneously - but it means jobs do not share files unless you use artifacts or declare dependencies with needs.

Runners are the machines

A runner is the virtual machine or container that executes a job. You pick one with runs-on. GitHub-hosted options include ubuntu-latest, windows-latest, and macos-latest. Every job starts on a clean runner, which guarantees reproducibility but also means nothing persists between jobs automatically.

.github/workflows/ci.yml
jobs:
  lint:
    runs-on: ubuntu-latest      # one runner
    steps:
      - uses: actions/checkout@v4
      - run: npm run lint
  test:
    runs-on: ubuntu-latest      # a separate runner, runs in parallel
    steps:
      - uses: actions/checkout@v4
      - run: npm test

Choosing a runner

  • Match the OS to your project - ubuntu-latest is the cheapest and fastest default.
  • Use macos-latest only when you need it (e.g. iOS builds); it costs more.
  • For lower cost and automatic retry of transient infrastructure failures, managed runner platforms like Latchkey are a drop-in alternative.

Key takeaways

  • Steps run sequentially on one shared runner; a failure stops the job.
  • Jobs run in parallel on separate, isolated runners by default.
  • Runners are fresh machines chosen with runs-on; nothing persists between jobs automatically.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →