Reuse workflows
Learn how to avoid duplication when creating a workflow by reusing existing workflows.
In this article
- Creating a reusable workflow
- Using inputs and secrets in a reusable workflow
- Calling a reusable workflow
- Passing inputs and secrets to a reusable workflow
- Using a matrix strategy with a reusable workflow
- Nesting reusable workflows
- Passing secrets to nested workflows
- Using outputs from a reusable workflow
- Monitoring which workflows are being used
- Next steps
Creating a reusable workflow
Reusable workflows are YAML-formatted files, very similar to any other workflow file. As with other workflow files, you locate reusable workflows in the.github/workflows
directory of a repository. Subdirectories of theworkflows
directory are not supported.
For a workflow to be reusable, the values foron
must includeworkflow_call
:
on:workflow_call:
Using inputs and secrets in a reusable workflow
You can define inputs and secrets, which can be passed from the caller workflow and then used within the called workflow. There are three stages to using an input or a secret in a reusable workflow.
In the reusable workflow, use the
inputs
andsecrets
keywords to define inputs or secrets that will be passed from a caller workflow.on:workflow_call:inputs:config-path:required:truetype:stringsecrets:personal_access_token:required:true
For details of the syntax for defining inputs and secrets, see
on.workflow_call.inputs
andon.workflow_call.secrets
.In the reusable workflow, reference the input or secret that you defined in the
on
key in the previous step.Note
If the secrets are inherited by using
secrets: inherit
in the calling workflow, you can reference them even if they are not explicitly defined in theon
key. For more information, seeWorkflow syntax for GitHub Actions.jobs:reusable_workflow_job:runs-on:ubuntu-lateststeps:-uses:actions/labeler@v4with:repo-token:${{secrets.personal_access_token}}configuration-path:${{inputs.config-path}}
In the example above,
personal_access_token
is a secret that's defined at the repository or organization level.Warning
Environment secrets cannot be passed from the caller workflow as
on.workflow_call
does not support theenvironment
keyword. If you includeenvironment
in the reusable workflow at the job level, the environment secret will be used, and not the secret passed from the caller workflow. For more information, seeManaging environments for deployment andWorkflow syntax for GitHub Actions.Pass the input or secret from the caller workflow.
To pass named inputs to a called workflow, use the
with
keyword in a job. Use thesecrets
keyword to pass named secrets. For inputs, the data type of the input value must match the type specified in the called workflow (either boolean, number, or string).jobs:call-workflow-passing-data:uses:octo-org/example-repo/.github/workflows/reusable-workflow.yml@mainwith:config-path:.github/labeler.ymlsecrets:personal_access_token:${{secrets.token}}
Workflows that call reusable workflows in the same organization or enterprise can use the
inherit
keyword to implicitly pass the secrets.jobs:call-workflow-passing-data:uses:octo-org/example-repo/.github/workflows/reusable-workflow.yml@mainwith:config-path:.github/labeler.ymlsecrets:inherit
Example reusable workflow
This reusable workflow file namedworkflow-B.yml
(we'll refer to this later in theexample caller workflow) takes an input string and a secret from the caller workflow and uses them in an action.
name: Reusable workflow exampleon: workflow_call: inputs: config-path: required: true type: string secrets: token: required: truejobs: triage: runs-on: ubuntu-latest steps: - uses: actions/labeler@v4 with: repo-token: ${{ secrets.token }} configuration-path: ${{ inputs.config-path }}
name:Reusableworkflowexampleon:workflow_call:inputs:config-path:required:truetype:stringsecrets:token:required:truejobs:triage:runs-on:ubuntu-lateststeps:-uses:actions/labeler@v4with:repo-token:${{secrets.token}}configuration-path:${{inputs.config-path}}
Calling a reusable workflow
You call a reusable workflow by using theuses
keyword. Unlike when you are using actions within a workflow, you call reusable workflows directly within a job, and not from within job steps.
You reference reusable workflow files using one of the following syntaxes:
{owner}/{repo}/.github/workflows/{filename}@{ref}
for reusable workflows in public and private repositories../.github/workflows/{filename}
for reusable workflows in the same repository.
In the first option,{ref}
can be a SHA, a release tag, or a branch name. If a release tag and a branch have the same name, the release tag takes precedence over the branch name. Using the commit SHA is the safest option for stability and security. For more information, seeSecure use reference.
If you use the second syntax option (without{owner}/{repo}
and@{ref}
) the called workflow is from the same commit as the caller workflow. Ref prefixes such asrefs/heads
andrefs/tags
are not allowed. You cannot use contexts or expressions in this keyword.
You can call multiple workflows, referencing each in a separate job.
jobs:call-workflow-1-in-local-repo:uses:octo-org/this-repo/.github/workflows/workflow-1.yml@172239021f7ba04fe7327647b213799853a9eb89call-workflow-2-in-local-repo:uses:./.github/workflows/workflow-2.ymlcall-workflow-in-another-repo:uses:octo-org/another-repo/.github/workflows/workflow.yml@v1
Example caller workflow
This workflow file calls two workflow files. The second of these,workflow-B.yml
(shown in theexample reusable workflow), is passed an input (config-path
) and a secret (token
).
name: Call a reusable workflowon: pull_request: branches: - mainjobs: call-workflow: uses: octo-org/example-repo/.github/workflows/workflow-A.yml@v1 call-workflow-passing-data: permissions: contents: read pull-requests: write uses: octo-org/example-repo/.github/workflows/workflow-B.yml@main with: config-path: .github/labeler.yml secrets: token: ${{ secrets.GITHUB_TOKEN }}
name:Callareusableworkflowon:pull_request:branches:-mainjobs:call-workflow:uses:octo-org/example-repo/.github/workflows/workflow-A.yml@v1call-workflow-passing-data:permissions:contents:readpull-requests:writeuses:octo-org/example-repo/.github/workflows/workflow-B.yml@mainwith:config-path:.github/labeler.ymlsecrets:token:${{secrets.GITHUB_TOKEN}}
Passing inputs and secrets to a reusable workflow
To pass named inputs to a called workflow, use thewith
keyword in a job. Use thesecrets
keyword to pass named secrets. For inputs, the data type of the input value must match the type specified in the called workflow (either boolean, number, or string).
jobs:call-workflow-passing-data:uses:octo-org/example-repo/.github/workflows/reusable-workflow.yml@mainwith:config-path:.github/labeler.ymlsecrets:personal_access_token:${{secrets.token}}
Workflows that call reusable workflows in the same organization or enterprise can use theinherit
keyword to implicitly pass the secrets.
jobs:call-workflow-passing-data:uses:octo-org/example-repo/.github/workflows/reusable-workflow.yml@mainwith:config-path:.github/labeler.ymlsecrets:inherit
Using a matrix strategy with a reusable workflow
Jobs using the matrix strategy can call a reusable workflow.
A matrix strategy lets you use variables in a single job definition to automatically create multiple job runs that are based on the combinations of the variables. For example, you can use a matrix strategy to pass different inputs to a reusable workflow. For more information about matrices, seeRunning variations of jobs in a workflow.
This example job below calls a reusable workflow and references the matrix context by defining the variabletarget
with the values[dev, stage, prod]
. It will run three jobs, one for each value in the variable.
jobs: ReusableMatrixJobForDeployment: strategy: matrix: target: [dev, stage, prod] uses: octocat/octo-repo/.github/workflows/deployment.yml@main with: target: ${{ matrix.target }}
jobs:ReusableMatrixJobForDeployment:strategy:matrix:target: [dev,stage,prod]uses:octocat/octo-repo/.github/workflows/deployment.yml@mainwith:target:${{matrix.target}}
Nesting reusable workflows
You can connect a maximum of four levels of workflows - that is, the top-level caller workflow and up to three levels of reusable workflows. For example:caller-workflow.yml →called-workflow-1.yml →called-workflow-2.yml →called-workflow-3.yml. Loops in the workflow tree are not permitted.
Note
Nested reusable workflows require all workflows in the chain to be accessible to the caller, and permissions can only be maintained or reduced—not elevated—throughout the chain. For more information, seeReusable workflows reference.
From within a reusable workflow you can call another reusable workflow.
name: Reusable workflowon: workflow_call:jobs: call-another-reusable: uses: octo-org/example-repo/.github/workflows/another-reusable.yml@v1
name:Reusableworkflowon:workflow_call:jobs:call-another-reusable:uses:octo-org/example-repo/.github/workflows/another-reusable.yml@v1
Passing secrets to nested workflows
You can usejobs.<job_id>.secrets
in a calling workflow to pass named secrets to a directly called workflow. Alternatively, you can usejobs.<job_id>.secrets.inherit
to pass all of the calling workflow's secrets to a directly called workflow. For more information, see the sectionReuse workflows above, and the reference articleWorkflow syntax for GitHub Actions. Secrets are only passed to directly called workflow, so in the workflow chain A > B > C, workflow C will only receive secrets from A if they have been passed from A to B, and then from B to C.
In the following example, workflow A passes all of its secrets to workflow B, by using theinherit
keyword, but workflow B only passes one secret to workflow C. Any of the other secrets passed to workflow B are not available to workflow C.
jobs:workflowA-calls-workflowB:uses:octo-org/example-repo/.github/workflows/B.yml@mainsecrets:inherit# pass all secrets
jobs:workflowB-calls-workflowC:uses:different-org/example-repo/.github/workflows/C.yml@mainsecrets:repo-token:${{secrets.personal_access_token}}# pass just this secret
Using outputs from a reusable workflow
A reusable workflow may generate data that you want to use in the caller workflow. To use these outputs, you must specify them as the outputs of the reusable workflow.
If a reusable workflow that sets an output is executed with a matrix strategy, the output will be the output set by the last successful completing reusable workflow of the matrix which actually sets a value.That means if the last successful completing reusable workflow sets an empty string for its output, and the second last successful completing reusable workflow sets an actual value for its output, the output will contain the value of the second last completing reusable workflow.
The following reusable workflow has a single job containing two steps. In each of these steps we set a single word as the output: "hello" and "world." In theoutputs
section of the job, we map these step outputs to job outputs called:output1
andoutput2
. In theon.workflow_call.outputs
section we then define two outputs for the workflow itself, one calledfirstword
which we map tooutput1
, and one calledsecondword
which we map tooutput2
.
Thevalue
must be set to the value of a job-level output within the called workflow. Step-level outputs must first be mapped to job-level outputs as shown below.
For more information, seePassing information between jobs andWorkflow syntax for GitHub Actions.
name: Reusable workflowon: workflow_call: # Map the workflow outputs to job outputs outputs: firstword: description: "The first output string" value: ${{ jobs.example_job.outputs.output1 }} secondword: description: "The second output string" value: ${{ jobs.example_job.outputs.output2 }}jobs: example_job: name: Generate output runs-on: ubuntu-latest # Map the job outputs to step outputs outputs: output1: ${{ steps.step1.outputs.firstword }} output2: ${{ steps.step2.outputs.secondword }} steps: - id: step1 run: echo "firstword=hello" >> $GITHUB_OUTPUT - id: step2 run: echo "secondword=world" >> $GITHUB_OUTPUT
name:Reusableworkflowon:workflow_call:# Map the workflow outputs to job outputsoutputs:firstword:description:"The first output string"value:${{jobs.example_job.outputs.output1}}secondword:description:"The second output string"value:${{jobs.example_job.outputs.output2}}jobs:example_job:name:Generateoutputruns-on:ubuntu-latest# Map the job outputs to step outputsoutputs:output1:${{steps.step1.outputs.firstword}}output2:${{steps.step2.outputs.secondword}}steps:-id:step1run:echo"firstword=hello">>$GITHUB_OUTPUT-id:step2run:echo"secondword=world">>$GITHUB_OUTPUT
We can now use the outputs in the caller workflow, in the same way you would use the outputs from a job within the same workflow. We reference the outputs using the names defined at the workflow level in the reusable workflow:firstword
andsecondword
. In this workflow,job1
calls the reusable workflow andjob2
prints the outputs from the reusable workflow ("hello world") to standard output in the workflow log.
name: Call a reusable workflow and use its outputson: workflow_dispatch:jobs: job1: uses: octo-org/example-repo/.github/workflows/called-workflow.yml@v1 job2: runs-on: ubuntu-latest needs: job1 steps: - run: echo ${{ needs.job1.outputs.firstword }} ${{ needs.job1.outputs.secondword }}
name:Callareusableworkflowanduseitsoutputson:workflow_dispatch:jobs:job1:uses:octo-org/example-repo/.github/workflows/called-workflow.yml@v1job2:runs-on:ubuntu-latestneeds:job1steps:-run:echo${{needs.job1.outputs.firstword}}${{needs.job1.outputs.secondword}}
For more information on using job outputs, seeWorkflow syntax for GitHub Actions. If you want to share something other than a variable (e.g. a build artifact) between workflows, seeStore and share data with workflow artifacts.
Monitoring which workflows are being used
Organizations that use GitHub Enterprise Cloud can interact with the audit log via the GitHub REST API to monitor which workflows are being used. For more information, seethe GitHub Enterprise Cloud documentation.
Next steps
To find information on the intricacies of reusing workflows, seeReusable workflows reference.