How to Build Reusable Github Actions Workflows with Workflow_call, Inputs, Secrets, and Outputs
Learning how to build reusable GitHub Actions workflows with workflow_call, inputs, secrets, and outputs is one of the smartest things you can do for your CI/CD pipeline. Instead of copying the same workflow YAML across multiple repositories, you define it once and call it from anywhere. This saves time, reduces errors, and keeps your automation consistent across projects. In this tutorial, you’ll create a reusable workflow that accepts inputs, handles secrets securely, and returns outputs to the calling workflow. Whether you’re managing WordPress deployments, Linux server scripts, or general application builds, this pattern applies directly. By the end, you’ll have a working reusable workflow setup you can adapt to any project.
Prerequisites for Building Reusable GitHub Actions Workflows
Before you start, make sure you have the following in place.
Required access and tools:
- A GitHub account with at least one repository
- Basic familiarity with YAML syntax
- Understanding of how standard GitHub Actions workflows work
- A second repository (or a second workflow in the same repo) to act as the caller
Assumed knowledge:
You should know how to create a .github/workflows/ directory and write a basic workflow file. You don’t need to be an expert. If you’ve run a workflow before, you’re ready.
Estimated time: 30–45 minutes.
You’ll also want to review the official GitHub Actions documentation on reusing workflows before you begin. It covers edge cases and permission models that are worth understanding early.
How to Build Reusable GitHub Actions Workflows Step by Step
For a related walkthrough, see: How to Configure MySQL Gtid-based Replication for Automatic Failover on Ubuntu
Follow these steps carefully. Each one builds on the last.
Step 1: Create the reusable workflow file
In your repository, create the directory .github/workflows/ if it doesn’t exist. Then create a file called reusable-deploy.yml inside it.
This file will contain your reusable workflow. The key trigger is workflow_call. This tells GitHub that other workflows can call this one directly.
name: Reusable Deploy Workflow
on:
workflow_call:
inputs:
environment:
required: true
type: string
app_name:
required: false
type: string
default: "my-app"
secrets:
DEPLOY_KEY:
required: true
outputs:
deploy_status:
description: "The result of the deployment"
value: ${{ jobs.deploy.outputs.status }}
Step 2: Define the job inside the reusable workflow
Below the on: block, add the jobs section. This is where your actual deployment logic lives.
jobs:
deploy:
runs-on: ubuntu-latest
outputs:
status: ${{ steps.run-deploy.outputs.result }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run deployment script
id: run-deploy
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
ENVIRONMENT: ${{ inputs.environment }}
APP_NAME: ${{ inputs.app_name }}
run: |
echo "Deploying $APP_NAME to $ENVIRONMENT"
echo "result=success" >> $GITHUB_OUTPUT
Notice how inputs and secrets are accessed using ${{ inputs.environment }} and ${{ secrets.DEPLOY_KEY }}. Outputs are written to the special $GITHUB_OUTPUT file. This is the modern approach GitHub recommends.
Step 3: Create the caller workflow
Now create a second workflow file. This one triggers on a push or pull request and calls your reusable workflow. Create .github/workflows/main.yml in your calling repository.
name: Main CI Pipeline
on:
push:
branches:
- main
jobs:
call-deploy:
uses: your-org/your-repo/.github/workflows/reusable-deploy.yml@main
with:
environment: "production"
app_name: "wordpress-site"
secrets:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
Replace your-org/your-repo with the actual path to the repository holding your reusable workflow. If both workflows are in the same repo, use the same repo path.
Step 4: Capture and use the output
You can read the output from the reusable workflow in a downstream job. Add a second job to your caller workflow like this:
check-result:
needs: call-deploy
runs-on: ubuntu-latest
steps:
- name: Print deploy status
run: echo "Deploy result was ${{ needs.call-deploy.outputs.deploy_status }}"
This job waits for call-deploy to finish. Then it prints the status returned by the reusable workflow.
Step 5: Store your secret in GitHub
Go to your repository settings. Click Secrets and variables, then Actions. Add a new secret called DEPLOY_KEY and paste your value. GitHub encrypts this automatically. Your workflow can now access it without exposing the value in logs.
Step 6: Commit and push both workflow files
Push your changes to the main branch. GitHub will detect the workflow files and run them on the next push event.
git add .github/workflows/
git commit -m "Add reusable deploy workflow with inputs, secrets, and outputs"
git push origin main
Check the Actions tab in your repository. You should see the Main CI Pipeline workflow run and call the reusable workflow successfully.
Troubleshooting Reusable Workflow Issues
Even clean setups run into problems. Here are the most common ones.
Error: “Workflow not found”
This happens when the path in your uses: field is wrong. Double-check the org name, repo name, file path, and branch reference. The format must be exactly org/repo/.github/workflows/file.yml@branch.
Secret not passed to reusable workflow
You must explicitly pass secrets in the caller using the secrets: block. They don’t pass automatically unless you use secrets: inherit. Use that option carefully. It exposes all parent secrets to the child workflow.
jobs:
call-deploy:
uses: your-org/your-repo/.github/workflows/reusable-deploy.yml@main
secrets: inherit
Output always returns empty
Make sure your step uses echo "key=value" >> $GITHUB_OUTPUT and not the older ::set-output syntax. GitHub deprecated the old method. Also verify the job-level outputs: block maps the step output correctly.
Input type mismatch
GitHub Actions inputs only support string, boolean, and number types for workflow_call. Passing an array or object will cause a validation error. Keep inputs simple and serialize complex data as strings if needed.
For a deeper look at input types and validation, check the GitHub workflow syntax reference for workflow_call inputs.
Conclusion: Reusable Workflows Save Time Across Every Project
You now know how to build reusable GitHub Actions workflows with workflow_call, inputs, secrets, and outputs. You created a reusable workflow file, defined typed inputs and encrypted secrets, returned outputs to the caller, and tested the full chain end to end. This pattern scales well. You can maintain one central workflow and call it from dozens of repositories without duplicating code. If your deployment logic changes, you update it in one place. Every caller picks up the change automatically. From WordPress site deployments to Linux server automation, reusable workflows cut maintenance overhead significantly. Your next step is to explore matrix strategies and conditional logic inside reusable workflows to handle more complex pipelines.
