Skip to main content

Creating Reusable Workflows

1. Defining Reusable Workflow

Property Description Values
name Name of the workflow string
on Triggers for the workflow workflow_call
inputs Inputs that can be passed to the workflow object
outputs Outputs that can be returned from the workflow object
jobs Jobs to run in the workflow object

Example: Defining a reusable workflow

name: "Reusable Workflow"
on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
    outputs:
      result:
        value: ${{ jobs.deploy.outputs.result }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to environment
        run: echo "Deploying to ${{ inputs.environment }}"
        id: deploy
      - name: Set output
        run: echo "result=success" >> $GITHUB_OUTPUT
        id: set_output

2. Calling Reusable Workflows

Parameter Description Example
uses The path to the reusable workflow file actions/reusable-workflow@v1
with Input parameters to pass to the reusable workflow environment: production
secrets Secrets to pass to the reusable workflow api_key: ${{ secrets.API_KEY }}

Example: Calling a Reusable Workflow

jobs:
  call-workflow:
    uses: octocat/my-reusable-workflow@v1
    with:
      environment: production
      timeout: 30m
    secrets:
      api_key: ${{ secrets.API_KEY }}
Note: Reusable workflows must be stored in the same repository or a public repository.
Warning: Ensure that all secrets used in the reusable workflow are properly scoped and accessible to the calling workflow.

3. Passing Inputs

Input Description Type Required
name The name of the input parameter string Yes
description A description of what the input is used for string No
required Whether the input is required or not boolean No
default The default value if the input is not provided string No
options A list of valid values for the input array No

Example: Using Inputs in a Workflow

name: Reusable Workflow
on:
  workflow_call:
    inputs:
      environment:
        description: 'The environment to deploy to'
        required: true
        type: string
        options:
          - production
          - staging
      debug:
        description: 'Enable debug mode'
        required: false
        type: boolean
        default: false
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to ${{ inputs.environment }}
        run: |
          echo "Deploying to ${{ inputs.environment }}"
          if ${{ inputs.debug }}; then
            echo "Debug mode enabled"
          fi

4. Defining Input Types

Input Type Description Example
string Text value, default is empty string name: 'environment'
number Numeric value, default is 0 timeout: 30
boolean True or false, default is false debug: true
environment Environment name, must match an existing environment environment: production
choice One of a predefined list of values mode: ['build', 'test', 'deploy']
file Path to a file, must be a valid path config-file: 'config.yaml'

Example: Defining Inputs in a Reusable Workflow

name: Reusable Workflow
on:
  workflow_call:
    inputs:
      environment:
        description: 'Environment to deploy to'
        required: true
        type: string
      debug:
        description: 'Enable debug mode'
        required: false
        type: boolean
        default: false
      timeout:
        description: 'Timeout in seconds'
        required: false
        type: number
        default: 30

5. Setting Required Inputs

Input Description Type Required
name The name of the input parameter string true
description A description of what the input is used for string false
required Whether the input is required or not boolean false
default The default value if the input is not provided string false
options A list of valid values for the input array false

Example: Defining Required Inputs

name: "Reusable Workflow"
inputs:
  environment:
    description: "The environment to deploy to"
    required: true
    type: string
  branch:
    description: "The branch to deploy from"
    required: false
    type: string
    default: "main"

6. Setting Default Input Values

Property Description Default Value Example
inputs.<input_name>.default Defines the default value for an input parameter if no value is provided. None
inputs:
  environment:
    description: 'Environment to deploy to'
    default: 'staging'

Example: Using Default Values in Workflow

name: Reusable Workflow with Defaults
on:
  workflow_call:
    inputs:
      environment:
        description: 'Environment to deploy to'
        type: string
        default: 'staging'
      debug:
        description: 'Enable debug mode'
        type: boolean
        default: false

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to ${{ inputs.environment }}
        run: |
          echo "Deploying to ${{ inputs.environment }}"
          if ${{ inputs.debug }}; then
            echo "Debug mode enabled"
          fi
Note: Default values are only used when the calling workflow does not provide a value for the input. If an input is required and no default is set, it must be provided by the caller.

7. Using Secrets in Reusable Workflows

Secret Usage Notes
GITHUB_TOKEN secrets.GITHUB_TOKEN Automatically provided by GitHub, no need to define
CUSTOM_SECRET secrets.CUSTOM_SECRET Must be defined in repository or organization settings

Example: Using a Secret in a Reusable Workflow

name: Reusable Workflow with Secrets
on:
  workflow_call:
    secrets:
      API_KEY:
        required: true
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Use Secret
        run: |
          echo "API Key is: ${{ secrets.API_KEY }}"
Note: Secrets are passed as inputs to reusable workflows and are not accessible in the calling workflow's context.

8. Returning Outputs

Property Description Example
outputs Defines the outputs that a reusable workflow can return to the calling workflow.
outputs:
  job-status:
    description: "Status of the job"
    value: ${{ jobs.job1.result }}

Example: Defining Outputs in a Reusable Workflow

name: Reusable Workflow with Outputs
on:
  workflow_call:
    outputs:
      job-status:
        description: "Status of the job"
        value: ${{ jobs.job1.result }}
jobs:
  job1:
    runs-on: ubuntu-latest
    steps:
      - name: Run a step
        run: echo "Hello World"

Example: Using Outputs in a Calling Workflow

name: Using Reusable Workflow Outputs
on:
  workflow_dispatch:
jobs:
  call-workflow:
    uses: octocat/my-reusable-workflow@v1
    with:
      input: "value"
    outputs:
      job-status: ${{ jobs.call-workflow.outputs.job-status }}

9. Accessing Caller Context

Property Description Example
github.event Full event payload from the caller workflow {"ref": "refs/heads/main", "repository": {"name": "my-repo"}}
github.event_name Name of the event that triggered the workflow push
github.workflow Name of the workflow that triggered the call Deploy to Production
github.actor User who triggered the workflow octocat
github.run_id Unique identifier for the current workflow run 123456789
github.run_number Sequential number of the current workflow run 1

Example: Using caller context in a reusable workflow

name: Reusable Workflow Example
on:
  workflow_call:
    inputs:
      environment:
        type: string
        required: true
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to ${{ inputs.environment }}
        run: |
          echo "Deploying to ${{ inputs.environment }}"
          echo "Triggered by ${{ github.actor }} on branch ${{ github.event.ref }}"
Note: The github.event object contains all the data from the original event that triggered the workflow call, including repository details and branch information.

10. Nesting Reusable Workflows

Reusable workflows in GitHub Actions can be nested to create complex, modular CI/CD pipelines. This allows you to compose workflows from other workflows, enabling better organization and code reuse.

Property Description Example
uses Specifies the reusable workflow to use. Can be a local path or a reference to another repository. uses: ./.github/workflows/reusable-workflow.yml
with Parameters to pass into the reusable workflow. with: { environment: prod }
secrets Secrets to pass into the reusable workflow. secrets: { token: ${{ secrets.GITHUB_TOKEN }}}

Example: Nesting Reusable Workflows

name: Main Workflow
on:
  push:
    branches: [ main ]

jobs:
  build-and-test:
    uses: ./.github/workflows/reusable-build.yml
    with:
      environment: prod
    secrets:
      token: ${{ secrets.GITHUB_TOKEN }}
Note: When nesting workflows, the parent workflow's context (e.g., github.ref, github.sha) is passed to the child workflow. You can override these values using with if needed.
Warning: Nested workflows do not inherit the permissions of the parent workflow. You must explicitly set permissions in each nested workflow.

11. Versioning Reusable Workflows

Version Type Description Usage Notes
Tagged Versions Using Git tags to version workflows uses: owner/repo@v1.2.3 Recommended for stable releases
Branch References Using branch names to reference workflows uses: owner/repo@main Not recommended for production due to instability
Commit SHAs Using full commit hashes to reference workflows uses: owner/repo@abc123def456 Most stable but least flexible

Example: Using Tagged Version

name: My Workflow
on:
  push:
    branches: [ main ]

jobs:
  build:
    uses: octocat/my-reusable-workflow@v1.2.3
Note: When using tagged versions, ensure the tag exists in the repository to avoid failures.
Warning: Using branch references (like main) can lead to unexpected behavior if the workflow changes without a version bump.

12. Sharing Across Repositories

GitHub Actions workflows can be shared across repositories using Reusable Workflows. These allow you to define a workflow in one repository and call it from another, promoting code reuse and consistency.

Feature Description Notes
reusable workflow A workflow defined in one repository that can be called from another. Can be stored in a different repository than the one using it.
workflow_call Trigger that enables a workflow to be called from another workflow. Must be defined in the reusable workflow file.
workflow_dispatch Enables manual triggering of a reusable workflow. Can be used with inputs to customize behavior.

Example: Reusable Workflow Definition

name: Reusable Workflow
on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to ${{ inputs.environment }}
        run: |
          echo "Deploying to ${{ inputs.environment }}"

Example: Using the Reusable Workflow

name: Use Reusable Workflow
on:
  push:
    branches: [ main ]
jobs:
  deploy:
    uses: owner/repo/.github/workflows/deploy.yml@v1
    with:
      environment: production
Note: Reusable workflows must be stored in the .github/workflows directory of the repository where they are defined.
Warning: When using reusable workflows, ensure that the calling repository has appropriate permissions to access the workflow in the source repository.

13. Testing Reusable Workflows

Example: Testing a Reusable Workflow

name: Test Reusable Workflow
on:
  pull_request:
    branches: [ main ]
jobs:
  test-workflow:
    uses: ./.github/workflows/reusable-workflow.yml
    with:
      environment: test
Property Description Values
uses Path to the reusable workflow file .github/workflows/reusable-workflow.yml
with.environment Environment variable passed to the workflow test
Note: Reusable workflows can be tested locally using the act tool or by running them in a test environment.
Warning: Ensure that all inputs and secrets used in the reusable workflow are properly mocked or provided during testing.

Was this article helpful?