Reusable & Composite Workflows
Stop copy-pasting YAML: factor shared steps into composite actions and shared jobs into reusable workflows.
When the same twenty lines of YAML appear in five workflows, it is time to extract. GitHub gives you two complementary tools.
Composite actions — reuse steps
A composite action bundles several steps behind a single uses:. It lives in an action.yml (in your repo or a shared one) and takes inputs. Reach for it when you repeat a sequence of steps — say checkout, setup, and install.
Reusable workflows — reuse whole jobs
A reusable workflow is a full workflow that other workflows call with uses: under a job. It is triggered by workflow_call, accepts typed inputs and secrets, and runs as its own job(s). Reach for it when you want to standardise an entire pipeline — like a shared deploy or release process — across many repos.
Which one?
| Composite action | Reusable workflow | |
|---|---|---|
| Reuses | a group of steps | a whole job / pipeline |
| Called from | a step (uses: in steps) | a job (uses: in jobs) |
| Own runner? | no — runs in caller's job | yes — its own job(s) |
Example
# .github/workflows/deploy.yml (reusable — note workflow_call)
name: Deploy
on:
workflow_call:
inputs:
environment: { required: true, type: string }
secrets:
token: { required: true }
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v4
- run: ./deploy.sh
env:
TOKEN: ${{ secrets.token }}
# --- another workflow calls it as a job ---
# jobs:
# staging:
# uses: ./.github/workflows/deploy.yml
# with: { environment: staging }
# secrets: { token: ${{ secrets.DEPLOY_TOKEN }} }When to use it
- A platform team publishes a reusable workflow for deploying to Kubernetes so each product team calls it with different inputs instead of copy-pasting 50 lines.
- A developer packages three common setup steps (checkout, Node setup, cache restore) into a composite action to keep all 12 workflow files DRY.
- An organisation enforces a standard security scan step across every repo by requiring teams to call the shared reusable workflow.
More examples
Define a reusable workflow
workflow_call makes this a reusable workflow; inputs and secrets define the contract callers must satisfy.
# .github/workflows/reusable-deploy.yml
name: Reusable Deploy
on:
workflow_call:
inputs:
environment:
required: true
type: string
secrets:
DEPLOY_KEY:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- run: ./scripts/deploy.sh
env:
KEY: ${{ secrets.DEPLOY_KEY }}Call the reusable workflow
The calling workflow references the reusable file by its full path and passes the required input and secret.
jobs:
deploy-staging:
uses: org/infra-workflows/.github/workflows/reusable-deploy.yml@main
with:
environment: staging
secrets:
DEPLOY_KEY: ${{ secrets.STAGING_DEPLOY_KEY }}Create a composite action
A composite action bundles multiple steps under a single uses: reference so callers replace three boilerplate steps with one line.
# .github/actions/setup-node-cached/action.yml
name: Setup Node with Cache
description: Checkout, setup Node, and restore npm cache
runs:
using: composite
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- run: npm ci
shell: bash
Discussion