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:
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.