Reusable Workflows and Composite Actions
Both reusable workflows and composite actions exist to stop you copy-pasting YAML, but they operate at different levels and are not interchangeable. A reusable workflow is a whole pipeline — its own jobs, its own runners — that another workflow invokes. A composite action bundles a sequence of steps behind a single uses: and runs inside a caller's job. Pick the wrong one and you spend the day fighting the tool.
The deciding question is altitude. If the thing you want to share needs multiple jobs, a matrix, or an environment gate, it has to be a reusable workflow. If it is a repeated run of steps inside one job — checkout, auth, build — it is a composite action.
workflow_call and invoked at the job level by another workflow. Use it when the shared unit needs multiple jobs, a matrix, or an environment gate.uses: and runs inside the caller's job on its runner. Use it for a repeated run of steps like checkout, auth, build.Reusable Workflows
A reusable workflow declares on: workflow_call and lists its inputs, secrets, and outputs. A caller invokes it with uses: at the job level, and the called workflow runs its own jobs on its own runners.
# .github/workflows/build.yml
on:
workflow_call:
inputs:
node: { type: string, default: '20' }
secrets:
TOKEN: { required: true }
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# caller
jobs:
call-build:
uses: ./.github/workflows/build.yml
with: { node: '22' }
secrets: inherit
Composite Actions
A composite action is an action.yml with runs.using: "composite" and a list of steps. It is referenced as one step inside any job and executes in that job's context — same filesystem, same token, same working directory.
name: setup-app
runs:
using: "composite"
steps:
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
shell: bash
Inputs, Outputs, Secrets
Composite actions take inputs and expose outputs like any action. Reusable workflows are stricter about secrets: nothing is inherited automatically, so you either list each secret under secrets: or pass secrets: inherit deliberately. Declaring typed inputs with defaults is what keeps a shared unit usable across repos.
Nesting and Limits
Reusable workflows nest up to ten levels deep, and a single workflow file can call up to fifty unique reusable workflows. Push past the nesting limit and the run fails outright, so deeply layered pipelines need to be flattened rather than chained further.
Choosing Between Them
Reach for a reusable workflow when you are sharing orchestration — multiple jobs, a matrix, environment gating. Reach for a composite action when you are packaging a step sequence that runs inside one existing job. Getting this split right up front avoids rewriting the shared unit later.
Reusable workflow — defines its own jobs and runs-on, can use a matrix and environments, and is called at the job level with explicit secrets: passing. Use it to share an entire pipeline.
Composite action — a sequence of steps with no job or runner of its own, called as one step inside the caller's job and inheriting that job's context and token. Use it to package a repeated step sequence like setup plus auth plus build. If you need multiple jobs or environment gating, it must be a reusable workflow.
- Reaching for a composite action when you need multiple jobs or an environment gate — composite actions are steps, not jobs.
- Forgetting to pass
secrets:to a reusable workflow — secrets are not inherited unless you writesecrets: inheritor list them. - Assuming a composite action gets its own runner, when it runs in the caller's job and sees the caller's filesystem and token.
- Hardcoding values that should be
inputs, so the "reusable" unit only works for the one repo it was written in. - Nesting reusable workflows beyond ten levels and hitting the hard limit, which fails the run.
- Use a reusable workflow with
workflow_callto share a full pipeline that has jobs, a matrix, or environments. - Use a composite action to package a repeated step sequence within a single job.
- Declare typed
inputswith defaults and pass secrets explicitly, usingsecrets: inheritonly when justified. - Expose
outputsfrom reusable workflows so callers can branch on the results. - Pin reusable workflows and composite actions to a commit SHA like any other
uses:reference.
include, CI/CD components, extendsCircleCI orbs and reusable commands/jobsAzure Pipelines step, job, and stage templatesJenkins shared librariesKnowledge Check
Which construct can define its own multiple jobs?
- A reusable workflow, which has its own
jobsandruns-on - A composite action, which can declare jobs under
runs - Both, since they are just two syntaxes for the same thing
- Neither; only the top-level workflow can have jobs
How do secrets reach a reusable workflow?
- They must be passed explicitly, by listing them under
secrets:or usingsecrets: inherit - They are inherited automatically from the calling workflow with no extra config
- They are read directly from the called workflow's own repository-level secret settings page
- Reusable workflows cannot receive any secrets from the caller at all
Why does a composite action share the caller's context?
- It has no job or runner of its own and executes as a step inside the caller's job
- It clones the caller's environment onto a fresh runner before its steps start
- It explicitly imports the caller's filesystem through a declared action input
- It does not; each composite action runs in a fully isolated context
What is the nesting limit for reusable workflows?
- Up to ten levels deep, with up to fifty unique reusable workflows from one caller
- Unlimited depth, constrained only by the job's overall run-time budget
- Two levels deep, the very same hard cap that applies to nested composite-action calls
- Sixteen levels deep with no limit on workflows per caller
You got correct