GitHub Actions Deep Dive â Workflows, Runners, Matrices, Reusable Workflows & Caching
In this tutorial, you'll learn about GitHub Actions Deep Dive. We cover key concepts, practical examples, and best practices.
GitHub Actions automates software workflows directly from your repository. This deep dive covers every major feature: workflow syntax, runner types, build matrices, deployment environments, reusable workflows, composite actions, self-hosted runners, dependency caching, OIDC for cloud authentication, and how to leverage the Actions marketplace.
What you'll learn: Complete workflow syntax with events, jobs, steps; matrix strategies for parallel testing; environment protection rules; reusable and composite workflows; self-hosted runner setup; caching dependencies; OIDC authentication to AWS/GCP/Azure. Why it matters: Actions is the most widely used CI/CD platform on GitHub powering millions of builds daily. Real-world use: DodaZIP runs 200+ Actions workflows daily â matrix tests across Node/Python versions, multi-arch Docker builds, and zero-downtime deployments via OIDC.
Learning Path
flowchart LR A["CI/CD Basics
Build & Test"] --> B["GitHub Actions
This Tutorial"] B --> C["Reusable Workflows
DRY Pipelines"] C --> D["OIDC & Deployments
Production CD"] B --> E["Composite Actions
Custom Steps"] style B fill:#f90,color:#fff,stroke-width:2px
Workflow Syntax
Every workflow lives in .github/workflows/*.yml:
name: CI Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: "0 6 * * 1" # 6 AM every Monday
env:
NODE_VERSION: "20"
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- run: npm ci
- run: npm test
Matrix Builds
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: [18, 20, 22]
exclude:
- os: windows-latest
node: 22
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm test
This generates 8 parallel jobs (3Ã3 minus 1 exclusion).
Environments and Protection Rules
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: production
url: https://app.example.com
steps:
- run: ./deploy.sh
Configure required reviewers, wait timer, and branch limits in the GitHub repo Settings â Environments.
Reusable Workflows
Call a workflow from another workflow:
# .github/workflows/ci.yml (caller)
jobs:
call-test:
uses: ./.github/workflows/test-reusable.yml
with:
node-version: "20"
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# .github/workflows/test-reusable.yml (reusable)
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
- run: echo "Testing with Node ${{ inputs.node-version }}"
Composite Actions
Package multiple steps into one action:
# .github/actions/setup-project/action.yml
name: "Setup Project"
description: "Checkout, install deps, cache"
inputs:
node-version:
default: "20"
runs:
using: "composite"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- run: npm ci
shell: bash
- run: npm run build
shell: bash
Use it in workflows:
steps:
- uses: ./.github/actions/setup-project
with:
node-version: "22"
Caching Dependencies
steps:
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ hashFiles('package-lock.json') }}
restore-keys: |
npm-
For multiple languages, use dedicated cache actions:
- uses: actions/setup-node@v4
with:
cache: "npm"
- uses: actions/setup-python@v5
with:
cache: "pip"
OIDC for Cloud Authentication
jobs:
deploy:
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
aws-region: us-east-1
- run: aws s3 sync ./dist s3://my-bucket
No long-lived secrets â AWS trusts the OIDC token issued by GitHub.
Self-Hosted Runners
jobs:
build:
runs-on: self-hosted
steps:
- run: make build
Install the runner on your machine:
# Download and configure
curl -O https://github.com/actions/runner/releases/download/v2.320.0/actions-runner-linux-x64-2.320.0.tar.gz
tar xzf actions-runner-linux-x64-2.320.0.tar.gz
./config.sh --url https://github.com/org/repo --token YOUR_TOKEN
./run.sh
Actions Marketplace
Popular actions from github.com/marketplace:
- uses: docker/login-action@v3
- uses: docker/build-push-action@v6
- uses: docker/metadata-action@v5
- uses: codecov/codecov-action@v5
- uses: actions/upload-artifact@v4
- uses: actions/download-artifact@v4
Common Errors
- Incorrect permissions for OIDC â The
id-token: writepermission is required. Without it, OIDC token exchange fails with a 403 error. - Secrets not passed to reusable workflows â Secrets must be explicitly mapped in the caller's
secrets:block. They are NOT inherited automatically. - Cache miss on every run â The cache key changes when
hashFilesinput changes. Userestore-keyswith a prefix fallback for partial cache hits. - Matrix explosion â A 4Ã4Ã4 matrix generates 64 jobs. Use
include/excludeto trim unnecessary combinations. - Self-hosted runner offline â If the runner agent stops or the machine reboots, queued jobs wait indefinitely. Set up the runner as a systemd service for auto-restart.
- Environment protection blocking deployment â If reviewers or wait timers are configured on the environment, the workflow pauses until approved. This is not a bug â it's the intended safety mechanism.
- Reusable workflow recursion limit â Workflows can call reusable workflows up to 4 levels deep. Beyond that, GitHub rejects the workflow.
workflow_dispatchmissing inputs â If you add inputs toworkflow_dispatchafter the workflow exists, previously queued runs may fail. Always set defaults.
Practice Questions
1. How do you prevent a matrix job from running on Windows with Node 22?
Use the exclude key: exclude: - os: <a href="/operating-systems/windows/">windows</a>-latest\n node: 22
2. What's the difference between uses: and run: in a step?
uses: calls an action (local, Marketplace, or Docker). run: executes a shell command directly.
3. How do you pass secrets to a reusable workflow?
Map them explicitly: secrets:\n NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
4. What permissions are needed for OIDC authentication?
permissions:\n id-token: write\n contents: read
5. Challenge: Multi-cloud deployment pipeline Write a workflow that: builds on a 3-OS matrix, runs tests with Node 20/22, publishes Docker images to both Docker Hub and ECR, deploys to staging via environment protection rules, and deploys to production after manual approval. Use OIDC for both AWS and Docker Hub authentication.
Mini Project: Monorepo CI with Matrix and Caching
name: Monorepo CI
on:
push:
branches: [main]
pull_request:
jobs:
detect-changes:
runs-on: ubuntu-latest
outputs:
packages: ${{ steps.filter.outputs.changes }}
steps:
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
api: ./api/**
web: ./web/**
test:
needs: detect-changes
strategy:
matrix:
package: ${{ fromJSON(needs.detect-changes.outputs.packages) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cd ${{ matrix.package }} && npm ci && npm test
FAQ
Related Tutorials
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro