Job Dependencies with needs

needs turns independent jobs into a graph. catalog needs syntax, so it waits for it, starts only if it succeeded, and can read its outputs:

The catalog job of fundamentals.ymlYAML
  catalog:
    needs: syntax
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v7
      - name: Count one genre
        env:
          GENRE: ${{ inputs.genre || 'Cooking' }}
          CHECKED: ${{ needs.syntax.outputs.checked }}
        run: |
          count=$(jq --arg g "$GENRE" '[.books[] | select(.genre==$g)] | length' db/seed.json)
          echo "$CHECKED files parse; $GENRE books: $count"

The value travels in three hops: the step appends checked=4 to the file named by $GITHUB_OUTPUT, the job maps it to outputs.checked, and the dependent job reads needs.syntax.outputs.checked. The manual run on ubuntu-26.04 printed 4 files parse; Fiction books: 1. Outputs are strings of up to 1 MB.

In push run 36130254896, syntax, shells and context started together at 11:35:56, catalog at 11:36:05 (three seconds after syntax ended) and report at 11:36:11. Each hop costs queueing and a fresh runner, so split jobs for parallelism or a gate, not for tidiness.