Jobs are isolated VMs. When job A builds something that job B needs to deploy, you need a bridge. This lesson teaches the two mechanisms: outputs for small data and artifacts for files.
The Problem: Jobs Don't Share State
Solution 1: Job Outputs (Small Values)
For passing strings between jobs — version numbers, image tags, URLs, flags.
Complete Pattern
jobs:
build:
runs-on: ubuntu-latest
# 1. Declare which outputs this job exposes
outputs:
version: ${{ steps.ver.outputs.value }}
image-tag: ${{ steps.tag.outputs.value }}
steps:
- uses: actions/checkout@v4
# 2. Set outputs from steps (must have id:)
- name: Get version
id: ver
run: echo "value=$(node -p 'require(\"./package.json\").version')" >> $GITHUB_OUTPUT
- name: Set image tag
id: tag
run: echo "value=sha-$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
deploy:
needs: build
runs-on: ubuntu-latest
steps:
# 3. Read outputs from the upstream job
- run: |
echo "Version: ${{ needs.build.outputs.version }}"
echo "Image: ${{ needs.build.outputs.image-tag }}"
Solution 2: Artifacts (Files)
For passing files between jobs — build output, test reports, binaries, Docker contexts.
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- name: Upload build
uses: actions/upload-artifact@v4
with:
name: app-build # artifact name
path: dist/ # what to upload
retention-days: 5 # auto-delete after 5 days
if-no-files-found: error # fail if dist/ is empty
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download build
uses: actions/download-artifact@v4
with:
name: app-build
path: dist/ # where to put it
- run: ls -la dist/ # Your files are here!
Outputs vs Artifacts: When to Use Which
| Job Outputs | Artifacts | |
|---|---|---|
| Data type | Strings (small values) | Files & directories |
| Size | ~1 MB total | 500 MB (free tier) |
| Examples | version, image tag, URL, boolean | dist/, test reports, binaries |
| Downloadable | No (only in workflow) | Yes (from Actions UI) |
| Lifetime | Current run only | Configurable (1-90 days) |
| Speed | Instant | Upload/download time |
Rule of thumb: If it's a string → output. If it's a file → artifact. If in doubt, ask: "Can I fit this in a single
echo statement?" Yes = output. No = artifact.
🏋️ Exercise: Build Once, Deploy Twice
Create a workflow that builds once and deploys the same artifact to staging and production:
# .github/workflows/build-deploy.yml
name: Build & Deploy
on: workflow_dispatch
jobs:
build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.info.outputs.version }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'npm' }
- run: npm ci && npm run build
- id: info
run: echo "version=$(node -p 'require(\"./package.json\").version')" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@v4
with: { name: app, path: dist/ }
deploy-staging:
needs: build
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/download-artifact@v4
with: { name: app, path: dist/ }
- run: echo "🚀 Deploying v${{ needs.build.outputs.version }} to staging"
- run: ls dist/
deploy-production:
needs: [build, deploy-staging]
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/download-artifact@v4
with: { name: app, path: dist/ }
- run: echo "🚀 Deploying v${{ needs.build.outputs.version }} to PRODUCTION"
Key principle: Build ONCE → deploy the SAME artifact to every environment. Never rebuild for production — that can introduce inconsistency.
🧠 Recall Check
- What file do you write to in order to set a step output?
- What's the syntax for reading job A's output "tag" from job B?
- Why should you build once and deploy the same artifact, rather than rebuilding per environment?
- Can you download an artifact from the GitHub Actions UI?
Reveal answers
$GITHUB_OUTPUT— e.g.,echo "key=value" >> $GITHUB_OUTPUT${{ needs.A.outputs.tag }}- Consistency. Rebuilding might pick up different dependency versions, different timestamps, or different env vars. The same binary that passed tests in CI should be exactly what goes to production.
- Yes. Artifacts appear at the bottom of the workflow run page as downloadable zip files.
You now have all the building blocks of a CI pipeline: triggers, jobs, steps, caching, secrets, environments, outputs, and artifacts. You can build production-quality CI workflows. Next: Matrix Builds — testing across multiple versions and platforms simultaneously.