Lesson 9 / 25
Outputs and Artifacts
Passing data between steps and jobs.
GITHUB_OUTPUT, job outputs, artifacts
A step writes outputs by appending name=value lines to the file at $GITHUB_OUTPUT; later steps read them as steps.<id>.outputs.<name>. To pass values to other jobs, map them to job outputs and read needs.<job>.outputs.<name>. Files (build results, reports) move between jobs as artifacts with upload-artifact and download-artifact. actionlint type-checks these references, so a misspelled output name is caught before running.
A typo in a job output reference, linted
I checked this workflow with actionlint 1.7.12 (actionlint -oneline .github/workflows/outputs.yml); the output and exit code are copied from that run. actionlint validates syntax, expressions, job dependencies and known actions offline; shellcheck was not installed, so shell scripts inside run: were not linted. The workflow was not executed on GitHub. The version job exposes an output named tag; the publish job reads needs.version.outputs.tagg, and actionlint reports that tagg is not defined.
name: Outputs
on: workflow_dispatch
jobs:
version:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.meta.outputs.tag }}
steps:
- id: meta
run: echo "tag=v1.4.${{ github.run_number }}" >> "$GITHUB_OUTPUT"
publish:
needs: version
runs-on: ubuntu-latest
steps:
- run: echo "Publishing ${{ needs.version.outputs.tagg }}"
Output:
.github/workflows/outputs.yml:18:35: property "tagg" is not defined in object type {tag: string} [expression]
(exit code 1)Never use set-output
The old ::set-output command is deprecated; write to $GITHUB_OUTPUT instead.
Quick check: How does one job read a value produced by another job?
- Through environment variables automatically
- Through a shared /tmp folder
- Through job outputs, via needs.<job>.outputs.<name>
- It cannot
Answer
Through job outputs, via needs.<job>.outputs.<name> — Explicit outputs cross job boundaries.