Skip to content
Latchkey

How to Drive Conditional Jobs From Job Outputs in CI

Job outputs are strings, so incremental gating hinges on comparing them exactly: needs.detect.outputs.flag == the string true, not a bare truthiness check.

Job outputs cross job boundaries only as strings. Compute a flag in a detect job, promote it to outputs:, and compare it as == 'true' in each dependent job. Getting the string comparison right is the whole trick.

Steps

  • In the detect job, write flag=true (or false) to $GITHUB_OUTPUT.
  • Map it under the job outputs: key.
  • In consumers, compare needs.detect.outputs.flag == 'true'.

Workflow

.github/workflows/ci.yml
jobs:
  detect:
    runs-on: ubuntu-latest
    outputs:
      run_e2e: ${{ steps.decide.outputs.run_e2e }}
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - id: decide
        run: |
          if git diff --name-only origin/main...HEAD | grep -q '^src/'; then
            echo "run_e2e=true" >> "$GITHUB_OUTPUT"
          else
            echo "run_e2e=false" >> "$GITHUB_OUTPUT"
          fi
  e2e:
    needs: detect
    if: needs.detect.outputs.run_e2e == 'true'
    runs-on: ubuntu-latest
    steps: [{ run: npm run test:e2e }]

Gotchas

  • Outputs are always strings; if: needs.detect.outputs.run_e2e (no comparison) is truthy for any non-empty string including "false".
  • An empty output is treated as false, which is easy to trip over if the producing step failed silently.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →