Video Thumbnail for Lesson
6.3: Reusable Workflows

Reusable workflows: share entire pipelines

Reusable workflows look like any other workflow, but they are triggered with workflow_call and run as jobs inside another workflow. They are useful when you want to enforce an entire pipeline (not just a handful of steps).

Documentation: https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows

on:
  workflow_call:
    inputs:
      foo:
        required: true
        type: string
      environment:
        description: "Target GitHub environment name (e.g. staging, production)"
        required: true
        type: string
    secrets:
      # NOTE: You can only pass repo/org secrets here, not environment secrets
      EXAMPLE_REPOSITORY_SECRET:
        required: true

jobs:
  reusable-workflow-job:
    environment: ${{ inputs.environment }}
    runs-on: ubuntu-24.04

    steps:
      - name: job in reusable workflow
        env:
          # explicit input
          FOO: ${{ inputs.foo }}
          # from repo/org level
          EXAMPLE_REPOSITORY_SECRET: ${{ secrets.EXAMPLE_REPOSITORY_SECRET }}
          # from the **environment** selected above
          EXAMPLE_ENVIRONMENT_SECRET: ${{ secrets.EXAMPLE_ENVIRONMENT_SECRET }}
          EXAMPLE_ENVIRONMENT_VARIABLE: ${{ vars.EXAMPLE_ENVIRONMENT_VARIABLE }}
        run: |
          echo "FOO                           = $FOO"
          echo "EXAMPLE_REPOSITORY_SECRET     = $EXAMPLE_REPOSITORY_SECRET"
          echo "EXAMPLE_ENVIRONMENT_SECRET    = $EXAMPLE_ENVIRONMENT_SECRET"
          echo "EXAMPLE_ENVIRONMENT_VARIABLE  = $EXAMPLE_ENVIRONMENT_VARIABLE"

The caller workflow invokes the reusable definition twice—once with a relative path (implicitly pinned to the current commit) and once by referencing the repository and commit SHA.

Notice how secrets: inherit is required to pull environment secrets through the staging invocation, whereas the production invocation only receives the explicitly forwarded repository secret.

jobs:
  call-reuseable-workflow-path:
    name: Invoke reuseable workflow with relative path
    uses: ./.github/workflows/06-authoring-actions--02-reuseable-workflows-source.yaml
    with:
      foo: bar
      environment: staging
    secrets: inherit

  call-reuseable-workflow-sha:
    name: Invoke reuseable workflow with repo + commit hash
    uses: sidpalas/devops-directive-github-actions-course/.github/workflows/06-authoring-actions--02-reuseable-workflows-source.yaml@f2d2e4a0a9ee82ef859e0f83ebfb5236efce069f
    with:
      foo: bar
      environment: production
    secrets:
      EXAMPLE_REPOSITORY_SECRET: ${{ secrets.EXAMPLE_REPOSITORY_SECRET }}

When to choose workflows vs. composite actions

  1. Only used once? Keep the logic inline in a normal workflow.
  2. Need to standardize the full pipeline? Use a reusable workflow so callers cannot modify the job sequence.
  3. Just sharing a handful of steps? Package them as a composite action for flexibility without copy/paste.