GitHub Actions Tutorial — Action Inputs & Outputs

2 minute read

Action Inputs & Outputs

Actions communicate through inputs (configuration you pass in) and outputs (data the action produces). Understanding this interface is key to chaining actions together effectively.


Passing Inputs with with:

The with: keyword passes inputs to an action:

steps:
  - uses: actions/setup-node@v4
    with:
      node-version: '20'
      cache: 'npm'

Each action defines its own inputs in its action.yml file. Check the action’s README or action.yml for available inputs.


Required vs Optional Inputs


# This action has both required and optional inputs
- uses: actions/upload-artifact@v4
  with:
    name: my-artifact         # required
    path: ./dist              # required
    retention-days: 5         # optional (default: 90)
    if-no-files-found: error  # optional (default: warn)

If you skip a required input, the action will fail with a clear error message.


Reading Action Outputs

Actions produce outputs that downstream steps can read. You need to:

  1. Give the step an id:
  2. Reference the output with ${{ steps.<id>.outputs.<name> }}

steps:
  - uses: actions/checkout@v4

  - name: Get changed files
    id: changes
    uses: dorny/paths-filter@v3
    with:
      filters: |
        src:
          - 'src/**'
        docs:
          - 'docs/**'

  - name: Use the output
    run: |
      echo "Source changed: ${{ steps.changes.outputs.src }}"
      echo "Docs changed: ${{ steps.changes.outputs.docs }}"


Real-World Example — Docker Build and Push


steps:
  - uses: actions/checkout@v4

  - name: Log in to Docker Hub
    uses: docker/login-action@v3
    with:
      username: ${{ secrets.DOCKER_USERNAME }}
      password: ${{ secrets.DOCKER_PASSWORD }}

  - name: Build and push
    id: docker-build
    uses: docker/build-push-action@v6
    with:
      context: .
      push: true
      tags: myorg/myapp:latest,myorg/myapp:${{ github.sha }}

  - name: Image digest
    run: echo "Digest: ${{ steps.docker-build.outputs.digest }}"

The docker/build-push-action produces outputs like digest and imageid that you can reference in later steps.


Passing Dynamic Values as Inputs

You can use expressions in with: values:


steps:
  - uses: actions/checkout@v4

  - name: Set version
    id: ver
    run: echo "tag=v$(date +%Y%m%d)-${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"

  - uses: docker/build-push-action@v6
    with:
      context: .
      push: true
      tags: myorg/myapp:${{ steps.ver.outputs.tag }}


Environment Variables vs Inputs

Mechanism Syntax When to Use
with: inputs with: key: value Configure an action
env: variables env: KEY: value Set env vars for run: commands

steps:
  # 'with:' configures the action's inputs
  - uses: actions/setup-node@v4
    with:
      node-version: '20'

  # 'env:' sets environment variables for shell commands
  - run: echo "API is $API_URL"
    env:
      API_URL: https://api.example.com


Common Mistakes

Mistake Fix
Output is empty Ensure the step has an id: and check the action docs for correct output name
Wrong input name Check the action’s action.yml for exact input names (case-sensitive)
Using env: instead of with: Actions read with: inputs; env: is for shell commands
Input type mismatch Some inputs expect strings even for booleans: 'true' not true

Quick Reference

Concept Syntax
Pass input with: key: value
Step ID id: my-step
Read output ${{ steps.my-step.outputs.name }}
Dynamic input with: tag: ${{ steps.ver.outputs.tag }}

← Previous: Checkout & Setup

Next: Step Outputs →

Updated: