GitHub Actions Reference: Workflows, Matrix Builds, Docker GHCR, OIDC & Reusable Workflows
GitHub Actions is GitHub’s built-in CI/CD platform. Workflows are YAML files in .github/workflows/ that trigger on push, PR, schedule, or manual dispatch — running jobs in parallel or series on GitHub-hosted or self-hosted runners.
1. Workflow Syntax Essentials
on triggers, jobs, steps, env, and context variables
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
paths: # only run if these paths change
- 'src/**'
- 'package.json'
pull_request:
branches: [main]
schedule:
- cron: '0 9 * * 1-5' # 9am weekdays UTC
workflow_dispatch: # manual trigger
inputs:
environment:
type: choice
options: [staging, production]
default: staging
jobs:
test:
runs-on: ubuntu-latest # or: macos-latest, windows-latest, ubuntu-22.04
timeout-minutes: 30 # fail job if it takes > 30min
env:
NODE_ENV: test
API_URL: https://api.staging.example.com
steps:
- name: Checkout code
uses: actions/checkout@v4 # most common first step
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm # built-in npm/yarn/pnpm cache
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
env:
DB_URL: ${{ secrets.TEST_DB_URL }} # from repo/org secrets
- name: Upload test results
if: failure() # only runs if previous step failed
uses: actions/upload-artifact@v4
with:
name: test-results
path: test-results/
2. Matrix Builds
Test across multiple versions and OS in parallel
jobs:
test:
strategy:
fail-fast: false # don't cancel other matrix jobs on failure
matrix:
python-version: ["3.10", "3.11", "3.12"]
os: [ubuntu-latest, macos-latest]
# Total: 3 × 2 = 6 parallel jobs
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- run: pip install -r requirements.txt && pytest
# Exclude specific combinations:
# matrix.exclude:
# - os: macos-latest
# python-version: "3.10"
# Add extra entries to the matrix:
# matrix.include:
# - os: ubuntu-latest
# python-version: "3.13-beta" # test pre-release
build:
needs: test # runs after ALL matrix test jobs pass
runs-on: ubuntu-latest
steps:
- run: echo "All tests passed, building..."
3. Docker Build & Push to GHCR
Build and push container images to GitHub Container Registry
jobs:
build-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # needed to push to GHCR
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} # auto-provided, no setup needed
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=ref,event=branch # branch name
type=semver,pattern={{version}} # git tag → version
type=sha,prefix=sha- # commit SHA
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: ${{ github.event_name != 'pull_request' }} # push only on merge
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha # use GitHub Actions cache for layers
cache-to: type=gha,mode=max
4. Reusable Workflows & Caching
DRY workflow composition and dependency caching
# Reusable workflow (define once, call from multiple workflows):
# .github/workflows/deploy.yml
on:
workflow_call: # makes this reusable
inputs:
environment:
required: true
type: string
secrets:
DEPLOY_KEY:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }} # environment protection rules apply
steps:
- run: echo "Deploying to ${{ inputs.environment }}"
# Call from another workflow:
# .github/workflows/cd.yml
jobs:
deploy-staging:
uses: ./.github/workflows/deploy.yml # local reusable workflow
with:
environment: staging
secrets:
DEPLOY_KEY: ${{ secrets.STAGING_DEPLOY_KEY }}
deploy-production:
needs: deploy-staging
uses: ./.github/workflows/deploy.yml
with:
environment: production
secrets:
DEPLOY_KEY: ${{ secrets.PROD_DEPLOY_KEY }}
# Cache dependencies (manual — for frameworks actions/setup-* don't cover):
- name: Cache pip packages
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
# Cache Go modules:
- uses: actions/cache@v4
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-go-${{ hashFiles('go.sum') }}
5. Secrets, OIDC & Environments
Secure secrets, AWS/GCP OIDC auth (no long-lived keys), and deployment environments
# Secrets: Settings → Secrets → Actions
# Access in workflow: ${{ secrets.MY_SECRET }}
# Organization secrets: available across repos
# Environment secrets: only available when running in that environment
# OIDC — authenticate to AWS without storing access keys:
jobs:
deploy:
permissions:
id-token: write # required for OIDC
contents: read
steps:
- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/github-actions-role
aws-region: us-east-1
# No secrets needed — GitHub mints a token, AWS validates it
# IAM trust policy must allow github.com OIDC provider + repo claim
- run: aws s3 ls my-bucket # authenticated via OIDC
# Deployment environments (require approval before deploying to production):
jobs:
deploy:
environment: production # waits for required reviewers
steps:
- run: echo "Deploying to production"
# Set up in: Settings → Environments → Required reviewers
# Concurrency (cancel in-progress runs when new commit pushed):
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # cancels previous run if new push arrives
# Conditional steps:
- name: Deploy only on main
if: github.ref == 'refs/heads/main'
run: ./deploy.sh
- name: Notify on failure
if: failure() && github.ref == 'refs/heads/main' # only alert on main failures
run: curl -X POST $SLACK_WEBHOOK -d '{"text":"Build failed!"}'
Track GitHub Actions, Node.js, Python, and CI/CD tool releases.
ReleaseRun monitors Kubernetes, Docker, and 13+ DevOps technologies.
Related: GitLab CI Reference | Tekton Reference | Trivy Reference
5 GitHub Actions Mistakes That Slow Down Every Build — quick visual guide, 2 min
🔍 Audit your actions: Paste your workflow YAML into the GitHub Actions Version Auditor — check every uses: pin against the latest release, see SHA vs tag pinning, and flag unverified publishers.
🔒 Security audit: Use the GitHub Actions Security Checker to scan your workflows for pull_request_target misuse, missing permissions blocks, and hardcoded secrets.
Founded
2023 in London, UK
Contact
hello@releaserun.com