Day 21intermediateFeb 21, 2026

DRY Your Pipelines with Reusable Workflows

Reusable workflows eliminate copy-paste duplication across repos and keep your CI/CD consistent.

cicdgithub-actionsbest-practices
Share:

What

Reusable workflows in GitHub Actions let you define a workflow once and call it from multiple other workflows. This eliminates copy-paste duplication across repositories and ensures consistency. You define the reusable workflow with the workflow_call trigger, specify its inputs and secrets, and then reference it from any calling workflow.

Why It Matters

When you have 10+ repositories with nearly identical CI pipelines, updating a single step means editing every repo. Reusable workflows let you maintain one source of truth. Change the reusable workflow once, and every repo that calls it picks up the update automatically β€” as long as callers reference a branch ref like @main rather than a pinned tag or SHA.

Example

# .github/workflows/reusable-test.yml (the reusable workflow)
name: Reusable Test
on:
  workflow_call:
    inputs:
      node-version:
        required: true
        type: string
    secrets:
      NPM_TOKEN:
        required: true

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
      - run: npm ci
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
      - run: npm test

# .github/workflows/ci.yml (the calling workflow)
name: CI
on: [push]

jobs:
  call-tests:
    uses: ./.github/workflows/reusable-test.yml
    with:
      node-version: '20'
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
yaml

Common Mistake

Not passing required secrets to the reusable workflow β€” they don't inherit automatically. Your workflow will fail with empty secret values unless you explicitly pass them or use secrets: inherit to forward all secrets from the caller.

Quick Fix

Use secrets: inherit in the calling workflow to pass all available secrets automatically, or explicitly list each secret the reusable workflow needs.

Key Takeaways

  • 1Define once with on: workflow_call, call from anywhere
  • 2Specify inputs and secrets the reusable workflow needs
  • 3Call with uses: ./.github/workflows/reusable.yml
  • 4Secrets don't inherit automatically β€” pass them explicitly
  • 5Use secrets: inherit to forward all secrets at once

Was this tip helpful?

Help us improve the DevOpsPath daily collection

Share: