Skip to content
GitHub Actions Deep Dive — Workflows, Runners, Matrices, Reusable Workflows & Caching

GitHub Actions Deep Dive — Workflows, Runners, Matrices, Reusable Workflows & Caching

DodaTech Updated Jun 20, 2026 6 min read

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<br/>Build & Test"] --> B["GitHub Actions<br/>This Tutorial"]
  B --> C["Reusable Workflows<br/>DRY Pipelines"]
  C --> D["OIDC & Deployments<br/>Production CD"]
  B --> E["Composite Actions<br/>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

  1. Incorrect permissions for OIDC — The id-token: write permission is required. Without it, OIDC token exchange fails with a 403 error.
  2. Secrets not passed to reusable workflows — Secrets must be explicitly mapped in the caller’s secrets: block. They are NOT inherited automatically.
  3. Cache miss on every run — The cache key changes when hashFiles input changes. Use restore-keys with a prefix fallback for partial cache hits.
  4. Matrix explosion — A 4×4×4 matrix generates 64 jobs. Use include/exclude to trim unnecessary combinations.
  5. 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.
  6. 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.
  7. Reusable workflow recursion limit — Workflows can call reusable workflows up to 4 levels deep. Beyond that, GitHub rejects the workflow.
  8. workflow_dispatch missing inputs — If you add inputs to workflow_dispatch after 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: windows-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

What’s the difference between reusable workflows and composite actions?
Reusable workflows are entire workflow files called from other workflows — they can have multiple jobs. Composite actions bundle multiple steps into a single action step.
How do I debug a failing workflow step?
Add ACTIONS_STEP_DEBUG: true to the workflow’s env block to enable diagnostic logging. You can also use actions/github-script for inline debugging.
Can I use GitHub Actions with GitLab or Bitbucket?
No. Actions is tightly integrated with GitHub. Use GitLab CI or Bitbucket Pipelines for those platforms.
How long can a workflow run?
Jobs timeout after 6 hours for hosted runners. Self-hosted runners can exceed this limit.
What’s the concurrency limit?
Free accounts: 20 concurrent jobs. Pro: 40. Enterprise: 180.

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