GitHub Actions Tutorial — Project: Reusable Library

2 minute read

Project: Reusable Workflow Library

Build an organization-wide shared workflow library with versioned reusable workflows that teams can call from their own repositories.


Requirements

Feature Implementation
Central workflow repository my-org/.github
Reusable CI workflow workflow_call with inputs
Reusable deploy workflow workflow_call with secrets
Versioned with tags Callers reference @v1
Works for Node.js and Python Language-specific inputs

Repository Structure

my-org/.github/
├── .github/
│   └── workflows/
│       ├── ci-node.yml          # reusable Node.js CI
│       ├── ci-python.yml        # reusable Python CI
│       └── deploy-s3.yml        # reusable S3 deploy
└── README.md

Reusable CI Workflow (Node.js)

.github/workflows/ci-node.yml:


name: Reusable Node.js CI

on:
  workflow_call:
    inputs:
      node-version:
        description: 'Node.js version'
        type: string
        default: '20'
      working-directory:
        description: 'Working directory'
        type: string
        default: '.'
      run-lint:
        description: 'Run linting'
        type: boolean
        default: true

jobs:
  ci:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ${{ inputs.working-directory }}
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
          cache: 'npm'
          cache-dependency-path: ${{ inputs.working-directory }}/package-lock.json

      - run: npm ci

      - name: Lint
        if: inputs.run-lint
        run: npm run lint

      - run: npm test


Reusable Deploy Workflow

.github/workflows/deploy-s3.yml:


name: Reusable S3 Deploy

on:
  workflow_call:
    inputs:
      environment:
        description: 'Target environment'
        type: string
        required: true
      s3-bucket:
        description: 'S3 bucket name'
        type: string
        required: true
      build-command:
        description: 'Build command'
        type: string
        default: 'npm run build'
      dist-path:
        description: 'Path to built assets'
        type: string
        default: 'dist'
    secrets:
      AWS_ROLE_ARN:
        required: true

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci
      - run: ${{ inputs.build-command }}

      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      - run: aws s3 sync ${{ inputs.dist-path }} s3://${{ inputs.s3-bucket }} --delete


Calling the Reusable Workflows

From any repository in the organization:


name: CI/CD

on:
  push:
    branches: [main]

jobs:
  ci:
    uses: my-org/.github/.github/workflows/ci-node.yml@v1
    with:
      node-version: '20'
      run-lint: true

  deploy-staging:
    needs: ci
    uses: my-org/.github/.github/workflows/deploy-s3.yml@v1
    with:
      environment: staging
      s3-bucket: my-app-staging
    secrets:
      AWS_ROLE_ARN: ${{ secrets.STAGING_AWS_ROLE }}

  deploy-production:
    needs: deploy-staging
    uses: my-org/.github/.github/workflows/deploy-s3.yml@v1
    with:
      environment: production
      s3-bucket: my-app-production
    secrets:
      AWS_ROLE_ARN: ${{ secrets.PROD_AWS_ROLE }}


Versioning the Library

# Tag a release
git tag v1.0.0
git push origin v1.0.0

# Maintain the major tag
git tag -fa v1 v1.0.0
git push origin v1 --force

Teams reference @v1 — they get patches and features automatically, breaking changes only in v2.


Design Decisions

Decision Reasoning
Central .github repo Organization-wide visibility
Inputs with defaults Flexible but easy to use with minimal config
Secrets passed explicitly Callers control which secrets flow in
Major version tags Teams update on their schedule

← Previous: Project — Multi-Env Deploy

Next: Project — Custom Action →

Updated: