instruction: How do you create a custom composite action in GitHub Actions?
output: Creating a composite action - GitHub Docs Skip to main content GitHub Docs Version: Free, Pro, &amp; Team Search or ask Copilot Search or ask Copilot Select language: current language is English Search or ask Copilot Search or ask Copilot Open menu Open Sidebar GitHub Actions / Tutorials / Create actions / Create a composite action Home GitHub Actions Get started Quickstart Understand GitHub Actions Continuous integration Continuous deployment Actions vs Apps Concepts Workflows and actions Workflows Variables Contexts Expressions Reusable workflows Custom actions Deployment environments Concurrency Workflow artifacts Dependency caching Notifications for workflow runs Runners GitHub-hosted runners Larger runners Self-hosted runners Private networking Runner groups Runner scale sets Actions Runner Controller Support for ARC Security Secrets GITHUB_TOKEN OpenID Connect Artifact attestations Script injections Compromised runners Kubernetes admissions controller Metrics Billing and usage How-tos Write workflows Use workflow templates Choose when workflows run Trigger a workflow Control jobs with conditions Control workflow concurrency Choose where workflows run Choose the runner for a job Run jobs in a container Choose what workflows do Use jobs Find and customize actions Use GitHub CLI Add scripts Use secrets Use variables Pass job outputs Set default values for jobs Deploy to environment Run job variations Reuse automations Reuse workflows Create workflow templates Share across private repositories Share with your organization Secure your work Use artifact attestations Use artifact attestations Increase security rating Enforce artifact attestations Verify attestations offline Manage attestations Security harden deployments OIDC in AWS OIDC in Azure OIDC in Google Cloud Platform OIDC in HashiCorp Vault OIDC in JFrog OIDC in PyPI OIDC in cloud providers OIDC with reusable workflows Deploy Configure and manage deployments Control deployments View deployment history Manage environments Review deployments Create custom protection rules Configure custom protection rules Deploy to third-party platforms Node.js to Azure App Service Python to Azure App Service Java to Azure App Service .NET to Azure App Service PHP to Azure App Service Docker to Azure App Service Azure Static Web App Azure Kubernetes Service Amazon Elastic Container Service Google Kubernetes Engine Sign Xcode applications Create and publish actions Manage custom actions Create a CLI action Set exit codes Publish in GitHub Marketplace Release and maintain actions Manage workflow runs Manually run a workflow Re-run workflows and jobs Cancel a workflow run Disable and enable workflows Skip workflow runs Delete a workflow run Download workflow artifacts Remove workflow artifacts Manage caches Approve runs from forks Manage runners GitHub-hosted runners Use GitHub-hosted runners Customize runners View current jobs Connect to a private network Connect with OIDC Connect with WireGuard Self-hosted runners Add runners Run scripts Customize containers Configure the application Use proxy servers Apply labels Use in a workflow Manage access Monitor and troubleshoot Remove runners Larger runners Manage larger runners Control access Use larger runners Monitor workflows Use the visualization graph View workflow run history View job execution time Add a status badge Use workflow run logs Enable debug logging Troubleshoot workflows Administer View metrics Get support Reference Workflows and actions Workflow syntax Events that trigger workflows Workflow commands Variables Expressions Contexts Deployments and environments Dependency caching Reusable workflows Metadata syntax Workflow cancellation Dockerfile support Runners GitHub-hosted runners Larger runners Self-hosted runners Security Secure use Secrets OIDC Limits GitHub Actions Importer Supplemental arguments and settings Custom transformers Tutorials Create an example workflow Build and test code Go Java with Ant Java with Gradle Java with Maven .NET Node.js PowerShell Python Ruby Rust Swift Xamarin apps Authenticate with GITHUB_TOKEN Create actions Create a JavaScript action Create a composite action Publish packages Publish Docker images Publish Java packages with Gradle Publish Java packages with Maven Publish Node.js packages Manage your work Add labels to issues Close inactive issues Add comments with labels Schedule issue creation Store and share data Use containerized services Create a Docker container action Use Docker service containers Create PostgreSQL service containers Create Redis service containers Migrate to GitHub Actions Automated migrations Use GitHub Actions Importer Azure DevOps migration Bamboo migration Bitbucket Pipelines migration CircleCI migration GitLab migration Jenkins migration Travis CI migration Manual migrations Migrate from Azure Pipelines Migrate from CircleCI Migrate from GitLab CI/CD Migrate from Jenkins Migrate from Travis CI Use Actions Runner Controller Quickstart Authenticate to the API Deploy runner scale sets Use ARC in a workflow Troubleshoot GitHub Actions / Tutorials / Create actions / Create a composite action Creating a composite action In this tutorial, you'll learn how to build a composite action. Platform navigation Mac Windows Linux In this article Introduction Prerequisites Creating an action metadata file Testing out your action in a workflow Creating a composite action within the same repository Example composite actions on GitHub Introduction In this guide, you'll learn about the basic components needed to create and use a packaged composite action. To focus this guide on the components needed to package the action, the functionality of the action's code is minimal. The action prints "Hello World" and then "Goodbye", or if you provide a custom name, it prints "Hello [who-to-greet]" and then "Goodbye". The action also maps a random number to the random-number output variable, and runs a script named goodbye.sh . Once you complete this project, you should understand how to build your own composite action and test it in a workflow. Warning When creating workflows and actions, you should always consider whether your code might execute untrusted input from possible attackers. Certain contexts should be treated as untrusted input, as an attacker could insert their own malicious content. For more information, see Secure use reference . Composite actions and reusable workflows Composite actions allow you to collect a series of workflow job steps into a single action which you can then run as a single job step in multiple workflows. Reusable workflows provide another way of avoiding duplication, by allowing you to run a complete workflow from within other workflows. For more information, see Reusable workflows . Prerequisites Note This example explains how to create a composite action within a separate repository. However, it is possible to create a composite action within the same repository. For more information, see Creating a composite action . Before you begin, you'll create a repository on GitHub. Create a new public repository on GitHub. You can choose any repository name, or use the following hello-world-composite-action example. You can add these files after your project has been pushed to GitHub. For more information, see Creating a new repository . Clone your repository to your computer. For more information, see Cloning a repository . From your terminal, change directories into your new repository. Shell cd hello-world-composite-action cd hello-world-composite-action In the hello-world-composite-action repository, create a new file called goodbye.sh with example code: Shell echo "echo Goodbye" > goodbye.sh echo "echo Goodbye" > goodbye.sh From your terminal, make goodbye.sh executable. Shell chmod +x goodbye.sh chmod +x goodbye.sh Shell chmod +x goodbye.sh chmod +x goodbye.sh Shell git add --chmod=+x -- goodbye.sh git add --chmod=+x -- goodbye.sh From your terminal, check in your goodbye.sh file. Shell git add goodbye.sh git commit -m "Add goodbye script" git push git add goodbye.sh git commit -m "Add goodbye script" git push Shell git add goodbye.sh git commit -m "Add goodbye script" git push git add goodbye.sh git commit -m "Add goodbye script" git push Shell git commit -m "Add goodbye script" git push git commit -m "Add goodbye script" git push Creating an action metadata file In the hello-world-composite-action repository, create a new file called action.yml and add the following example code. For more information about this syntax, see Metadata syntax reference . YAML name: 'Hello World' description: 'Greet someone' inputs: who-to-greet: # id of input description: 'Who to greet' required: true default: 'World' outputs: random-number: description: "Random number" value: ${{ steps.random-number-generator.outputs.random-number }} runs: using: "composite" steps: - name: Set Greeting run: echo "Hello $INPUT_WHO_TO_GREET." shell: bash env: INPUT_WHO_TO_GREET: ${{ inputs.who-to-greet }} - name: Random Number Generator id: random-number-generator run: echo "random-number=$(echo $RANDOM)" >> $GITHUB_OUTPUT shell: bash - name: Set GitHub Path run: echo "$GITHUB_ACTION_PATH" >> $GITHUB_PATH shell: bash env: GITHUB_ACTION_PATH: ${{ github.action_path }} - name: Run goodbye.sh run: goodbye.sh shell: bash name: 'Hello World' description: 'Greet someone' inputs: who-to-greet: # id of input description: 'Who to greet' required: true default: 'World' outputs: random-number: description: "Random number" value: ${{ steps.random-number-generator.outputs.random-number }} runs: using: "composite" steps: - name: Set Greeting run: echo "Hello $INPUT_WHO_TO_GREET." shell: bash env: INPUT_WHO_TO_GREET: ${{ inputs.who-to-greet }} - name: Random Number Generator id: random-number-generator run: echo "random-number=$(echo $RANDOM)" >> $GITHUB_OUTPUT shell: bash - name: Set GitHub Path run: echo "$GITHUB_ACTION_PATH" >> $GITHUB_PATH shell: bash env: GITHUB_ACTION_PATH: ${{ github.action_path }} - name: Run goodbye.sh run: goodbye.sh shell: bash This file defines the who-to-greet input, maps the random generated number to the random-number output variable, adds the action's path to the runner system path (to locate the goodbye.sh script during execution), and runs the goodbye.sh script. For more information about managing outputs, see Metadata syntax reference . For more information about how to use github.action_path , see Contexts reference . From your terminal, check in your action.yml file. Shell git add action.yml git commit -m "Add action" git push git add action.yml git commit -m "Add action" git push From your terminal, add a tag. This example uses a tag called v1 . For more information, see About custom actions . Shell git tag -a -m "Description of this release" v1 git push --follow-tags git tag -a -m "Description of this release" v1 git push --follow-tags Testing out your action in a workflow The following workflow code uses the completed hello world action that you made in Creating a composite action . Copy the workflow code into a .github/workflows/main.yml file in another repository, replacing OWNER and SHA with the repository owner and the SHA of the commit you want to use, respectively. You can also replace the who-to-greet input with your name. YAML on: [push] jobs: hello_world_job: runs-on: ubuntu-latest name: A job to say hello steps: - uses: actions/checkout@v4 - id: foo uses: OWNER/hello-world-composite-action@SHA with: who-to-greet: 'Mona the Octocat' - run: echo random-number "$RANDOM_NUMBER" shell: bash env: RANDOM_NUMBER: ${{ steps.foo.outputs.random-number }} on: [ push ] jobs: hello_world_job: runs-on: ubuntu-latest name: A job to say hello steps: - uses: actions/checkout@v4 - id: foo uses: OWNER/hello-world-composite-action@SHA with: who-to-greet: 'Mona the Octocat' - run: echo random-number "$RANDOM_NUMBER" shell: bash env: RANDOM_NUMBER: ${{ steps.foo.outputs.random-number }} From your repository, click the Actions tab, and select the latest workflow run. The output should include: "Hello Mona the Octocat", the result of the "Goodbye" script, and a random number. Creating a composite action within the same repository Create a new subfolder called hello-world-composite-action , this can be placed in any subfolder within the repository. However, it is recommended that this be placed in the .github/actions subfolder to make organization easier. In the hello-world-composite-action folder, do the same steps to create the goodbye.sh script Shell echo "echo Goodbye" > goodbye.sh echo "echo Goodbye" > goodbye.sh Shell chmod +x goodbye.sh chmod +x goodbye.sh Shell chmod +x goodbye.sh chmod +x goodbye.sh Shell git add --chmod=+x -- goodbye.sh git add --chmod=+x -- goodbye.sh Shell git add goodbye.sh git commit -m "Add goodbye script" git push git add goodbye.sh git commit -m "Add goodbye script" git push Shell git add goodbye.sh git commit -m "Add goodbye script" git push git add goodbye.sh git commit -m "Add goodbye script" git push Shell git commit -m "Add goodbye script" git push git commit -m "Add goodbye script" git push In the hello-world-composite-action folder, create the action.yml file based on the steps in Creating a composite action . When using the action, use the relative path to the folder where the composite action's action.yml file is located in the uses key. The below example assumes it is in the .github/actions/hello-world-composite-action folder. YAML on: [push] jobs: hello_world_job: runs-on: ubuntu-latest name: A job to say hello steps: - uses: actions/checkout@v4 - id: foo uses: ./.github/actions/hello-world-composite-action with: who-to-greet: 'Mona the Octocat' - run: echo random-number "$RANDOM_NUMBER" shell: bash env: RANDOM_NUMBER: ${{ steps.foo.outputs.random-number }} on: [ push ] jobs: hello_world_job: runs-on: ubuntu-latest name: A job to say hello steps: - uses: actions/checkout@v4 - id: foo uses: ./.github/actions/hello-world-composite-action with: who-to-greet: 'Mona the Octocat' - run: echo random-number "$RANDOM_NUMBER" shell: bash env: RANDOM_NUMBER: ${{ steps.foo.outputs.random-number }} Example composite actions on GitHub You can find many examples of composite actions on GitHub. microsoft/action-python microsoft/gpt-review tailscale/github-action Help and support Get quick answers! Ask Copilot your question. Ask Copilot Did you find what you needed? Yes No Privacy policy Help us make these docs great! All GitHub docs are open source. See something that&#x27;s wrong or unclear? Submit a pull request. Make a contribution Learn how to contribute Still need help? Ask the GitHub community Contact support Legal © 2025 GitHub, Inc. Terms Privacy Status Pricing Expert services Blog