--- title: Reusing workflow configurations shortTitle: Reusing workflow configurations intro: Find information about avoiding duplication when creating a workflow by reusing existing workflows{% ifversion fpt or ghec %} and using YAML anchors and aliases{% endif %}. versions: fpt: '*' ghec: '*' ghes: '*' redirect_from: - /actions/reference/reusable-workflows-reference - /actions/reference/workflows-and-actions/reusable-workflows --- ## Reusable workflows Reference information for reusable workflows. ### Access to reusable workflows A reusable workflow can be used by another workflow if any of the following is true: * Both workflows are in the same repository. * The called workflow is stored in a public repository{% ifversion ghes %} on {% data variables.product.prodname_ghe_server %}. You cannot directly use reusable workflows defined on {% data variables.product.prodname_dotcom_the_website %}. Instead store a copy of the reusable workflow on {% data variables.location.product_location %}, and call the workflow from that path. {% elsif actions-workflow-policy %}, and your {% ifversion ghec %}enterprise{% else %}organization{% endif %} allows you to use public reusable workflows.{% endif %}{% ifversion ghes or ghec %} * The called workflow is stored in an internal repository and the settings for that repository allow it to be accessed. For more information, see [AUTOTITLE](/actions/creating-actions/sharing-actions-and-workflows-with-your-enterprise).{% endif %} * The called workflow is stored in a private repository and the settings for that repository allow it to be accessed. For more information, see {% ifversion ghes or ghec %}[AUTOTITLE](/actions/creating-actions/sharing-actions-and-workflows-with-your-enterprise).{% else %}[AUTOTITLE](/actions/creating-actions/sharing-actions-and-workflows-with-your-organization) and [AUTOTITLE](/actions/creating-actions/sharing-actions-and-workflows-from-your-private-repository).{% endif %} The following table shows the accessibility of reusable workflows to a caller workflow, depending on the visibility of the host repository. | Caller repository | Accessible workflows repositories | |----|----| | `private` | `private`{% ifversion ghes or ghec %}, `internal`,{% endif %} and `public` | | {% ifversion ghes or ghec %} | | `internal` | `internal`, and `public` | | {% endif %} | | `public` | `public` | The **Actions permissions** on the callers repository's Actions settings page must be configured to allow the use of actions and reusable workflows - see [AUTOTITLE](/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#allowing-select-actions-and-reusable-workflows-to-run). For {% ifversion ghes or ghec %}internal or {% endif %}private repositories, the **Access** policy on the Actions settings page of the called workflow's repository must be explicitly configured to allow access from repositories containing caller workflows - see [AUTOTITLE](/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#allowing-access-to-components-in-a-private-repository). {% data reusables.actions.actions-redirects-workflows %} ### Limitations of reusable workflows * You can connect up to {% ifversion fpt or ghec %}ten {% else %}four {% endif %}levels of workflows. For more information, see [Nesting reusable workflows](/actions/how-tos/sharing-automations/reuse-workflows#nesting-reusable-workflows). * You can call a maximum of {% ifversion fpt or ghec %}50 {% else %}20 {% endif %}unique reusable workflows from a single workflow file. This limit includes any trees of nested reusable workflows that may be called starting from your top-level caller workflow file. For example, _top-level-caller-workflow.yml_ → _called-workflow-1.yml_ → _called-workflow-2.yml_ counts as 2 reusable workflows. * Any environment variables set in an `env` context defined at the workflow level in the caller workflow are not propagated to the called workflow. For more information, see [AUTOTITLE](/actions/learn-github-actions/variables) and [AUTOTITLE](/actions/learn-github-actions/contexts#env-context). * Similarly, environment variables set in the `env` context, defined in the called workflow, are not accessible in the `env` context of the caller workflow. Instead, you must use outputs of the reusable workflow. For more information, see [Using outputs from a reusable workflow](/actions/how-tos/sharing-automations/reuse-workflows#using-outputs-from-a-reusable-workflow). * To reuse variables in multiple workflows, set them at the organization, repository, or environment levels and reference them using the `vars` context. For more information see [AUTOTITLE](/actions/learn-github-actions/variables) and [AUTOTITLE](/actions/learn-github-actions/contexts#vars-context). * Reusable workflows are called directly within a job, and not from within a job step. You cannot, therefore, use `GITHUB_ENV` to pass values to job steps in the caller workflow. ### Supported keywords for jobs that call a reusable workflow When you call a reusable workflow, you can only use the following keywords in the job containing the call: * [`jobs..name`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idname) * [`jobs..uses`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_iduses) * [`jobs..with`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idwith) * [`jobs..with.`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idwithinput_id) * [`jobs..secrets`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idsecrets) * [`jobs..secrets.`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idsecretssecret_id) * [`jobs..secrets.inherit`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idsecretsinherit) * [`jobs..strategy`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategy) * [`jobs..needs`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds) * [`jobs..if`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idif) * [`jobs..concurrency`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idconcurrency) * [`jobs..permissions`](/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idpermissions) > [!NOTE] > > * If `jobs..permissions` is not specified in the calling job, the called workflow will have the default permissions for the `GITHUB_TOKEN`. For more information, see [AUTOTITLE](/actions/reference/workflow-syntax-for-github-actions#permissions). > * The `GITHUB_TOKEN` permissions passed from the caller workflow can be only downgraded (not elevated) by the called workflow. > * If you use `jobs..concurrency.cancel-in-progress: true`, don't use the same value for `jobs..concurrency.group` in the called and caller workflows as this will cause the workflow that's already running to be cancelled. A called workflow uses the name of its caller workflow in {% raw %}${{ github.workflow }}{% endraw %}, so using this context as the value of `jobs..concurrency.group` in both caller and called workflows will cause the caller workflow to be cancelled when the called workflow runs. ### How reusable workflows use runners #### {% data variables.product.github %}-hosted runners The assignment of {% data variables.product.prodname_dotcom %}-hosted runners is always evaluated using only the caller's context. Billing for {% data variables.product.prodname_dotcom %}-hosted runners is always associated with the caller. The caller workflow cannot use {% data variables.product.prodname_dotcom %}-hosted runners from the called repository. For more information, see [AUTOTITLE](/actions/using-github-hosted-runners/about-github-hosted-runners). #### Self-hosted runners Called workflows that are owned by the same user or organization{% ifversion ghes or ghec %} or enterprise{% endif %} as the caller workflow can access self-hosted runners from the caller's context. This means that a called workflow can access self-hosted runners that are: * In the caller repository * In the caller repository's organization{% ifversion ghes or ghec %} or enterprise{% endif %}, provided that the runner has been made available to the caller repository ### Access and permissions for nested workflows A workflow that contains nested reusable workflows will fail if any of the nested workflows is inaccessible to the initial caller workflow. For more information, see [Access to reusable workflows](#access-to-reusable-workflows). `GITHUB_TOKEN` permissions can only be the same or more restrictive in nested workflows. For example, in the workflow chain A > B > C, if workflow A has `package: read` token permission, then B and C cannot have `package: write` permission. For more information, see [AUTOTITLE](/actions/security-guides/automatic-token-authentication). For information on how to use the API to determine which workflow files were involved in a particular workflow run, see [AUTOTITLE](/actions/how-tos/sharing-automations/reuse-workflows#monitoring-which-workflows-are-being-used). ### Behavior of reusable workflows when re-running jobs {% data reusables.actions.partial-reruns-with-reusable %} ### `github` context When a reusable workflow is triggered by a caller workflow, the `github` context is always associated with the caller workflow. The called workflow is automatically granted access to `github.token` and `secrets.GITHUB_TOKEN`. For more information about the `github` context, see [AUTOTITLE](/actions/learn-github-actions/contexts#github-context). ## Workflow templates Reference information to use when creating workflow templates for your organization. ### Workflow template availability You can use templates in repositories that match or have more restricted visibility than the template repository. * Workflow templates in a public `.github` repository are available to all repository types. * Workflow templates in an internal `.github` repository are only available to internal and private repositories. * Workflow templates in a private `.github` repository are only available to private repositories. {% ifversion ghec %} Because public workflow templates require a public `.github` repository, they are not available for {% data variables.product.prodname_emus %}. {% endif %} ### Granting access for private/internal repositories If you're using a private or internal `.github` repository, you need to grant Read access to users or teams who should be able to use the templates. ### The `$default-branch` placeholder If you need to refer to a repository's default branch, you can use the `$default-branch` placeholder in your workflow template. When a workflow is created the placeholder will be automatically replaced with the name of the repository's default branch. {% ifversion ghes %} ### Placeholder values in the `runs-on` key The following values in the `runs-on` key are also treated as placeholders: * `ubuntu-latest` is replaced with `[ self-hosted ]` * `windows-latest` is replaced with `[ self-hosted, windows ]` * `macos-latest"` is replaced with `[ self-hosted, macOS ]` {% endif %} ### Example workflow template file This file named `octo-organization-ci.yml` demonstrates a basic workflow. ```yaml copy name: Octo Organization CI on: push: branches: [ $default-branch ] pull_request: branches: [ $default-branch ] jobs: build: runs-on: ubuntu-latest steps: - uses: {% data reusables.actions.action-checkout %} - name: Run a one-line script run: echo Hello from Octo Organization ``` ### Metadata file requirements The metadata file must have the same name as the workflow file, but instead of the `.yml` extension, it must be appended with `.properties.json`. For example, this file named `octo-organization-ci.properties.json` contains the metadata for a workflow file named `octo-organization-ci.yml`: {% data reusables.actions.workflow-templates-metadata-example %} {% data reusables.actions.workflow-templates-metadata-keys %} {% ifversion fpt or ghec %} ## YAML anchors and aliases You can use YAML anchors and aliases to reduce repetition in your workflows. An anchor (marked with `&`) identifies a piece of content that you want to reuse, while an alias (marked with `*`) repeats that content in another location. For detailed information about anchors and aliases, see [Node Anchors and Aliases in the YAML specification](https://yaml.org/spec/1.2.2/#3222-anchors-and-aliases). Here's an example that uses YAML anchors and aliases with environment variables: ```yaml jobs: job1: env: &env_vars # Define the anchor on first use NODE_ENV: production DATABASE_URL: {% raw %}${{ secrets.DATABASE_URL }}{% endraw %} steps: - run: echo "Using production settings" job2: env: *env_vars # Reuse the environment variables steps: - run: echo "Same environment variables here" ``` This is equivalent to writing the following YAML without anchors and aliases: ```yaml jobs: job1: env: NODE_ENV: production DATABASE_URL: {% raw %}${{ secrets.DATABASE_URL }}{% endraw %} steps: - run: echo "Using production settings" job2: env: NODE_ENV: production DATABASE_URL: {% raw %}${{ secrets.DATABASE_URL }}{% endraw %} steps: - run: echo "Same environment variables here" ``` You can also use anchors for more complex configurations, such as reusing an entire job configuration: ```yaml jobs: test: &base_job # Define the anchor on first use runs-on: ubuntu-latest timeout-minutes: 30 env: NODE_VERSION: '18' steps: - uses: {% data reusables.actions.action-checkout %} - name: Set up Node.js uses: {% data reusables.actions.action-setup-node %} with: node-version: {% raw %}${{ env.NODE_VERSION }}{% endraw %} - run: npm test alt-test: *base_job # Reuse the entire job configuration ``` {% endif %}