Multiple jobs and needs

GitHub Actions · Essentials · 8 min

Real pipelines lint, test and deploy in separate jobs; needs is how you express what waits for what.

Jobs in a workflow start in parallel. To order them, a job lists the jobs it depends on in needs. GitHub builds a graph from these edges: a job starts when all of its needs have succeeded, and if one of them fails the dependent job is skipped.

deploy:
  needs: [lint, test]

Because each job runs on a fresh runner, anything a later job needs must be passed explicitly: build files go through artifacts, small values through job outputs, both covered later. Each job also re-checks out the code.

Useful job-level keys:

  • runs-on: different jobs can use different operating systems.
  • timeout-minutes: the default is 360 minutes, far too long for most CI. Set something realistic.
  • if:: skip the job conditionally, for example only deploy from main.
  • continue-on-error: true: let the workflow succeed even if this job fails (for experimental checks).
  • container: and services:: run the job inside a Docker image, or start side containers such as a database for tests (Linux runners only).

The Actions UI draws the graph, so a good structure doubles as documentation: fast checks first, slow or privileged jobs only after them.

Example

jobs:
  lint:
    runs-on: ubuntu-latest
    steps: [{uses: actions/checkout@v7}, {run: make lint}]
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    services:
      postgres:
        image: postgres:17
        env: {POSTGRES_PASSWORD: pw}
        ports: ["5432:5432"]
    steps: [{uses: actions/checkout@v7}, {run: make test}]
  deploy:
    needs: [lint, test]        # waits for both; skipped if either fails
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps: [{run: echo deploying}]

Remember

  • Jobs run in parallel unless needs orders them
  • A failed dependency skips the dependent job
  • Set timeout-minutes; the default is 6 hours

Watch out for

  • Writing files in one job and expecting the next job to find them on disk.

Check yourself

  1. Job C has needs: [A, B]. A succeeds, B fails. What happens to C?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-jobs-in-a-workflow