Git, CI/CD & GitOpsXLVII · Pipeline DependenciesDataflow
Outputs as inputs — the typed contract between jobs
What you'll learn
- Declare a job output with `outputs:` and set it from a step
- Consume an output via `needs.<job_id>.outputs.<name>`
- Distinguish outputs (typed, ephemeral) from artifacts (untyped, durable)
- Recognise the limits: outputs are strings, scoped to one run
Prerequisites
Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x
Jobs can declare outputs and pass them to
dependents. The producer promises a name and a
string; the consumer reads via
needs.<job_id>.outputs.<name>. One graph, two
contracts: ordering and data.
Declaring outputs
The producer declares outputs at job level:
jobs:
build:
runs-on: ubuntu-latest
outputs:
version: ${ steps.set-version.outputs.version }
digest: ${ steps.set-digest.outputs.digest }
steps:
- id: set-version
run: echo "version=1.2.3" >> "$GITHUB_OUTPUT"
- id: set-digest
run: echo "digest=sha256:abc..." >> "$GITHUB_OUTPUT"
The outputs: block maps names to expressions that
resolve at job-completion time.
Setting outputs from a step
The $GITHUB_OUTPUT file is the runtime:
echo "version=1.2.3" >> "$GITHUB_OUTPUT"
echo "digest=$(sha256sum package.tar | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
The runner captures each line as a named output.
Consuming outputs
A dependent reads via needs.<job_id>.outputs.<name>:
jobs:
deploy:
runs-on: ubuntu-latest
needs: [build]
steps:
- run: |
echo "Deploying ${ needs.build.outputs.version }"
echo "Digest ${ needs.build.outputs.digest }"
The dependent must list the producer in needs:.
The typed contract
Outputs are strings. No schema validation; contract by convention.
flowchart LR
B["build"] -->|outputs.version| D["deploy"]
B -->|outputs.digest| D
Edges carry ordering (needs:) and data
(outputs.<name>).
Outputs versus artifacts
- Outputs: typed, ephemeral, scoped to one run.
- Artifacts: untyped, durable, retained for
retention-days.
# Outputs
echo "version=1.2.3" >> "$GITHUB_OUTPUT"
# Artifacts
- uses: actions/upload-artifact@v4
with:
name: package
path: dist/package.tar
Outputs for values; artifacts for files.
Production discipline
- Declare every output the consumer needs.
- Validate shape at consumer if it matters.
- Artifacts for files; outputs for values.
- Document the output contract.
Cross-course references
- Ansible for Production Sysadmins - Part XXXVII uses AWX survey fields.
- Linux for Production Sysadmins - Part XXX uses EnvironmentFile.
Quiz
Knowledge check · 4 questions
Q1. Job A has `outputs: version`. Job B has `needs: [A]` and reads `needs.A.outputs.version`. What type is the value?
Q2. Outputs are visible to any job in the workflow, regardless of whether the consuming job declares the producer in `needs:`.
Q3. Name three limits of GitHub Actions outputs and explain why each matters.
Q4. Diagnose why a deploy job reports version as empty and recommend the fix.
Team P: build sets `outputs.version` via `echo "version=1.2.3" >> $GITHUB_OUTPUT`. deploy has `needs: [build]` and reads `needs.build.outputs.version`. Deploy reports empty.
Passing score: 75%. Answers are checked in this browser.