Skip to content

GitHub Actions: CI/CD Pipelines for Your Repositories

DodaTech Updated 2026-06-22 5 min read

GitHub Actions are event-driven workflows defined in YAML files that automate testing, building, and deploying code directly from your repository.

In this tutorial, you'll learn GitHub Actions for continuous integration and deployment. GitHub Actions automates testing, building, and deploying your code directly from your repository. By the end, you'll write custom workflows, use matrix builds, cache dependencies, and deploy applications to cloud platforms.

flowchart TD
  A[Push code] --> B[Workflow triggered]
  B --> C[Job 1: Lint]
  B --> D[Job 2: Test]
  D --> E{Matrix: OS x Version}
  E --> F[Ubuntu + Node 18]
  E --> G[Ubuntu + Node 20]
  E --> H[Windows + Node 18]
  C --> I[Job 3: Deploy]
  D --> I
  I --> J[Deploy to production]

Writing Your First Workflow

Create .github/workflows/ci.yml:

name: CI Pipeline
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 18
      - run: npm ci
      - run: npm test

Push this file and see the workflow run. The on key defines triggers — when the workflow runs. Jobs run on runners (virtual machines). Steps are individual commands or actions.

Matrix Builds

Test across multiple OS and language versions:

jobs:
  test:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
        node: [16, 18, 20]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci
      - run: npm test

Expected output: 6 parallel jobs (3 Node versions x 2 OS) run simultaneously.

Caching Dependencies

Speed up workflows by caching:

- name: Cache npm
  uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

Deploying to Cloud

Deploy to AWS after tests pass:

jobs:
  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - run: npm run build
      - name: Deploy to S3
        run: |
          aws s3 sync build/ s3://my-app-bucket
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

Workflow Components

Component Description Example
name Workflow display name CI Pipeline
on Trigger events push, pull_request, schedule
jobs Collection of jobs test, build, deploy
runs-on Runner OS ubuntu-latest, <a href="/operating-systems/windows/">windows</a>-latest
steps Commands or actions run: npm test
<a href="/design-patterns/strategy/">strategy</a>.matrix Multi-version testing node: [16, 18]
needs Job dependencies needs: test
secrets Encrypted variables ${{ secrets.MY_SECRET }}

Workflow Trigger Events

GitHub Actions supports many trigger events:

on:
  push:
    branches: [main, develop]
    paths: ["src/**", "tests/**"]
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened]
  schedule:
    - cron: "0 6 * * 1"  # Every Monday at 6 AM
  workflow_dispatch:  # Manual trigger
    inputs:
      environment:
        type: choice
        options: [staging, production]
  release:
    types: [published]

Self-Hosted Runners

For custom infrastructure, host your own runners:

jobs:
  deploy:
    runs-on: self-hosted
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to internal server
        run: ./deploy-internal.sh

Register a self-hosted runner in Settings > Actions > Runners. Use them for GPU builds, internal network access, or cost savings.

Using Reusable Workflows

Avoid duplication by calling shared workflows:

# .github/workflows/ci.yml
jobs:
  call-lint:
    uses: your-org/shared-workflows/.github/workflows/lint.yml@v1
    with:
      node-version: 18

  call-test:
    uses: your-org/shared-workflows/.github/workflows/test.yml@v1
    secrets:
      coveralls-token: ${{ secrets.COVERALLS_TOKEN }}

Common Errors

Error Cause Fix
No workflow found Wrong file location File must be in .github/workflows/
Syntax error Bad YAML Validate YAML online before committing
Command not found Missing setup step Add setup action before running commands
Resource not accessible Wrong permissions Add contents: read permission
Secret not found Secret not defined Add secret in repo Settings > Secrets
Workflow not running Trigger doesn't match Check branch name and event type
Matrix too large Too many combinations Limit matrix or use max-parallel
Job timeout Execution too long Increase timeout-minutes or optimize

Practice Questions

What is a GitHub Actions runner?

A runner is a virtual machine or self-hosted server that executes workflow jobs. GitHub provides hosted runners (Ubuntu, Windows, macOS) or you can host your own for custom environments or cost savings.

How do I trigger a workflow on a schedule?

Use the schedule event with cron syntax: on: schedule: - cron: '0 8 * * 1' runs every Monday at 8 AM. The cron expression uses standard cron format (minute, hour, day, month, weekday).

What is a matrix build?

A matrix build runs jobs across multiple combinations of OS, language versions, or other variables. For example, testing on Ubuntu, Windows, and macOS with Node.js 16, 18, and 20 — 9 total combinations — to ensure cross-platform compatibility.

How do I pass data between jobs?

Use artifacts. The first job uploads files with actions/upload-artifact, and the next job downloads them with actions/download-artifact. Artifacts persist after the workflow completes.

What are environment secrets?

Environment secrets are encrypted variables scoped to specific deployment environments (development, staging, production). They are accessed via ${{ secrets.NAME }} and never appear in logs. Set them in Repository > Settings > Secrets and variables > Actions

Challenge

Create a GitHub Actions workflow for a Node.js project that: lints on every push, runs tests on pull requests with a matrix of Node 18 and 20, caches dependencies, and deploys to a staging environment only when tests pass on the main branch. Include a scheduled weekly dependency audit.

Real-World Task

Set up a complete CI/CD pipeline for a Python project using GitHub Actions. The pipeline should run linting (flake8), tests (pytest), build a Docker image, push it to Docker Hub, and deploy to a Kubernetes cluster on main branch pushes. Use secrets for Docker credentials and Kube config. This mirrors the deployment pipeline at DodaTech for DodaZIP's backend services.


Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro