self-host →

Trigger a workflow from another workflow with GitHub Actions

Learn how to trigger a workflow from another workflow, even from another repository, using a GitHub App token and not personal access tokens.

When you dispatch an event (such as workflow_dispatch) using the default ${{ secrets.GITHUB_TOKEN }}, GitHub deliberately does not start a new workflow run. This is a built-in safeguard to prevent runaway recursive runs. To actually trigger another workflow you must authenticate with a different identity — a GitHub App token (recommended) or a personal access token (PAT).

This guide uses a GitHub App token, which is scoped to specific repositories, short-lived, and not tied to an individual user account. The same limitation applies even within a single repository, so the GitHub App approach below works for both same-repository and cross-repository triggers.

Step 1: Create the GitHub App#

  1. Go to your GitHub account settings and create a new GitHub App.
  2. Generate a private key for the app and note down the App ID.
  3. Install the GitHub App on the repository where you want to trigger the workflow.

Step 2: Store the credentials#

  1. Add the App ID and the private key as secrets in your repository settings. Name them APP_ID and APP_PRIVATE_KEY respectively (these are the names referenced in the workflow below).

Step 3: Create the triggered workflow#

Create a workflow file (e.g., .github/workflows/triggered-workflow.yml) that will be triggered by another workflow.

my-org/triggered-repo/.github/workflows/triggered-workflow.yml
name: Triggered Workflow
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Run a script
run: echo "This is the triggered workflow"

Step 4: Create the triggering workflow#

Create another workflow file (e.g., .github/workflows/triggering-workflow.yml) that will trigger the above workflow.

my-org/triggering-repo/.github/workflows/triggering-workflow.yml
name: Triggering Workflow
on:
push:
branches:
- main
jobs:
trigger:
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
id: generate_token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ secrets.APP_ID }}
private-key: ${{ secrets.APP_PRIVATE_KEY }}
# By default the token is scoped to the current repository only.
# When dispatching to a different repository, scope it explicitly:
owner: my-org
repositories: triggered-repo
- name: Trigger another workflow
uses: benc-uk/workflow-dispatch@v1
with:
workflow: triggered-workflow.yml
token: ${{ steps.generate_token.outputs.token }}
repo: my-org/triggered-repo
ref: main

Explanation#

  1. Triggered Workflow:

    • This workflow (triggered-workflow.yml) is set to run on the workflow_dispatch event, which allows it to be triggered manually or by another workflow.
  2. Triggering Workflow:

    • This workflow (triggering-workflow.yml) runs on a push to the main branch.
    • It uses the actions/create-github-app-token action to generate a GitHub App token using the App ID and private key stored in the APP_ID and APP_PRIVATE_KEY repository secrets.
    • The owner and repositories inputs scope the token to the target repository. By default the token only has access to the repository running the workflow, so these are required when dispatching to a different repository. For a same-repository trigger you can omit them.
    • It uses the benc-uk/workflow-dispatch action to trigger the triggered-workflow.yml by dispatching a workflow dispatch event.
    • The workflow input specifies the workflow file to be triggered.
    • The token input uses the generated GitHub App token.
    • The repo input specifies the repository where the event should be dispatched.
    • The ref input specifies the branch or tag to use for the triggered workflow run.

Note#

  • The GitHub App needs the Actions: Read and write repository permission to dispatch workflow events, and it must be installed on the target repository.
  • For a cross-repository setup, the App must be installed on the repository that owns the triggered workflow (my-org/triggered-repo above), since that is where the dispatch event is delivered.
  • When the App token is generated, it is scoped to the repositories where the App is installed and expires after a short time (about one hour), which is what makes it safer than a long-lived personal access token.