GitHub Actions Tutorial — Project: Reusable Library
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 →