GitHub Actions Cheatsheet
Reusable Workflows
Use this GitHub Actions reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
What are Reusable Workflows
A reusable workflow is a regular workflow file that exposes workflow_call as a trigger. Other workflows invoke it with uses: at the job level — not the step level. This enables DRY CI/CD across repos.
Defining a Reusable Workflow
# .github/workflows/deploy.yml (in the called repo) name: Deploy (reusable) on: workflow_call: inputs: environment: description: 'Target environment' required: true type: string image-tag: required: false type: string default: latest secrets: deploy-key: required: true api-token: required: false outputs: url: description: 'Deployed URL' value: ${{ jobs.deploy.outputs.url }} jobs: deploy: runs-on: ubuntu-latest environment: ${{ inputs.environment }} outputs: url: ${{ steps.deploy.outputs.url }} steps: - id: deploy run: | ./deploy.sh "${{ inputs.environment }}" "${{ inputs.image-tag }}" echo "url=https://${{ inputs.environment }}.example.com" >> $GITHUB_OUTPUT env: DEPLOY_KEY: ${{ secrets.deploy-key }}
Calling a Reusable Workflow
# .github/workflows/ci-cd.yml (in the caller repo) name: CI/CD on: push: branches: [main] jobs: build: uses: ./.github/workflows/build.yml # same-repo reference deploy-staging: needs: build uses: my-org/platform/.github/workflows/deploy.yml@main # cross-repo with: environment: staging image-tag: ${{ needs.build.outputs.image-tag }} secrets: deploy-key: ${{ secrets.STAGING_DEPLOY_KEY }} deploy-production: needs: deploy-staging uses: my-org/platform/.github/workflows/deploy.yml@v2.1.0 with: environment: production secrets: inherit # pass ALL caller secrets automatically
Input Types
| Type | Values |
|---|---|
string | Any text |
number | Numeric |
boolean | true / false |
inputs:
environment:
type: string
required: true
replicas:
type: number
default: 2
debug:
type: boolean
default: falsesecrets: inherit
Pass all secrets from the caller to the called workflow without listing them explicitly:
jobs:
deploy:
uses: ./.github/workflows/deploy.yml
with:
environment: production
secrets: inheritUse with caution — the called workflow gains access to all caller secrets.
Outputs Between Workflows
# Called workflow
jobs:
build:
outputs:
version: ${{ steps.v.outputs.version }}
steps:
- id: v
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
# Caller workflow
jobs:
build:
uses: ./.github/workflows/build.yml
release:
needs: build
runs-on: ubuntu-latest
steps:
- run: echo "Version = ${{ needs.build.outputs.version }}"Outputs must be declared at both the step, job, and workflow_call output levels to propagate.
Nesting Reusable Workflows
caller.yml → ci.yml (reusable) → lint.yml (reusable) ← up to 4 levels deep
Max nesting depth: 4 levels. A single caller can call multiple reusable workflows in parallel.
Referencing a Reusable Workflow
| Reference form | Example |
|---|---|
| Same repo, branch | ./.github/workflows/build.yml |
| Same repo, specific branch/tag | ./.github/workflows/build.yml@v1 |
| External repo, branch | owner/repo/.github/workflows/build.yml@main |
| External repo, tag | owner/repo/.github/workflows/build.yml@v2.1.0 |
| External repo, SHA | owner/repo/.github/workflows/build.yml@abc1234 |
Permissions in Reusable Workflows
The called workflow runs with the caller's GITHUB_TOKEN and inherits its permission scope. Declare permissions in the called workflow to request what it needs:
# called workflow
jobs:
deploy:
permissions:
contents: read
id-token: write
runs-on: ubuntu-latest
...Composite Actions vs Reusable Workflows
| Feature | Composite Action | Reusable Workflow |
|---|---|---|
| Unit | Step | Job(s) |
| Invoked with | uses: in a step | uses: as a whole job |
| Can use services | No | Yes |
| Can use matrix | No | Yes |
| Can set job outputs | No (only step) | Yes |
| Can specify runner | No | Yes |
| Nesting | Any depth | 4 levels |
| Use case | Reusable step logic | Full CI/CD pipelines |
Calling with Matrix
jobs:
deploy:
strategy:
matrix:
env: [dev, staging, production]
uses: ./.github/workflows/deploy.yml
with:
environment: ${{ matrix.env }}
secrets: inheritWorkflow Templates (Organization Level)
Store workflow templates in a repo named .github (at the org level):
.github/
workflow-templates/
ci.yml
ci.properties.jsonProperties file:
{
"name": "Standard CI",
"description": "Node.js CI template",
"iconName": "example-icon",
"categories": ["Node"]
}Members see these templates when creating new workflows in the org.