# Outputs and Artifacts — GitHub Actions

Source: https://www.skillbyai.com/en/github-actions/j-outputs

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

```yaml
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.

**Quiz:** How does one job read a value produced by another job?

- [ ] Through environment variables automatically
- [ ] Through a shared /tmp folder
- [x] Through job outputs, via needs.<job>.outputs.<name>
- [ ] It cannot

*Answer:* Through job outputs, via needs.<job>.outputs.<name>. Explicit outputs cross job boundaries.
