🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

How to Set Up a CI/CD Pipeline with GitHub Actions in 2026: Complete Guide

⏱️4 min read  ·  764 words

GitHub Actions is the most popular CI/CD platform in 2026 — built into GitHub, with a huge marketplace of pre-made actions. This guide builds a complete pipeline from testing to deployment, entirely in YAML files in your repo.

How GitHub Actions Works

Workflows live in .github/workflows/*.yml. Each workflow triggers on events (push, pull request, schedule) and contains jobs that run on runners (GitHub-hosted VMs). Jobs contain steps — either shell commands or reusable actions.

Basic CI Workflow

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci
      - run: npm run lint
      - run: npm test
      - run: npm run build

Matrix Builds (Test Multiple Versions)

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node: [18, 20, 22]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci
      - run: npm test
# Runs 9 combinations (3 OS x 3 Node versions) in parallel

Caching Dependencies

steps:
  - uses: actions/checkout@v4

  # setup-node has built-in caching
  - uses: actions/setup-node@v4
    with:
      node-version: '20'
      cache: 'npm'   # caches ~/.npm automatically

  # Or cache manually for other tools
  - uses: actions/cache@v4
    with:
      path: |
        ~/.cache/pip
        .venv
      key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}

Building and Pushing Docker Images

name: Build and Push

on:
  push:
    branches: [main]

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: |
            ghcr.io/${{ github.repository }}:latest
            ghcr.io/${{ github.repository }}:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Deployment with Environments and Approvals

jobs:
  deploy:
    runs-on: ubuntu-latest
    needs: [test]           # only deploy if tests pass
    environment:
      name: production      # can require manual approval in repo settings
      url: https://example.com
    steps:
      - uses: actions/checkout@v4

      - name: Deploy via SSH
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.PROD_HOST }}
          username: ${{ secrets.DEPLOY_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /app
            docker compose pull
            docker compose up -d

Managing Secrets

Store secrets in repo Settings, then Secrets and variables, then Actions. Reference them as ${{ secrets.NAME }}. They’re masked in logs and never exposed. Use environment-specific secrets for staging vs production.

steps:
  - run: ./deploy.sh
    env:
      API_KEY: ${{ secrets.API_KEY }}
      DATABASE_URL: ${{ secrets.DATABASE_URL }}

Reusable Workflows and Composite Actions

# Call a reusable workflow to avoid duplication
jobs:
  call-shared:
    uses: ./.github/workflows/shared-test.yml
    with:
      node-version: '20'
    secrets: inherit

# shared-test.yml declares:
# on:
#   workflow_call:
#     inputs:
#       node-version:
#         type: string

Optimization Tips

  • Use needs: to control job order and run independent jobs in parallel
  • Cache dependencies — the biggest speedup for most pipelines
  • Cancel outdated runs: concurrency: { group: ${{ github.ref }}, cancel-in-progress: true }
  • Use path filters: only run workflows when relevant files change
  • Pin action versions (@v4) for stability and security

Frequently Asked Questions

Q: GitHub Actions vs GitLab CI vs Jenkins?
A: GitHub Actions if your code is on GitHub — deep integration and a huge marketplace. GitLab CI for GitLab-hosted code. Jenkins for maximum control/self-hosting or complex enterprise needs. Actions is the easiest for GitHub projects.

Q: Is GitHub Actions free?
A: Public repos get unlimited free minutes. Private repos get a monthly free allotment, then pay per minute. For most small projects and open source, it’s effectively free.

Q: How do I speed up slow workflows?
A: Cache dependencies (biggest win), run jobs in parallel with needs:, use path filters to skip irrelevant runs, and cancel outdated runs with concurrency groups. Profile which steps are slowest first.

Q: How do I require approval before production deploys?
A: Use GitHub Environments with required reviewers. Configure the production environment in repo settings to require manual approval — the deploy job pauses until an approved reviewer confirms.

Q: Can I run workflows on a schedule?
A: Yes — use on: schedule: - cron: '0 0 * * *' for scheduled runs (nightly builds, cleanup jobs, periodic checks). Cron syntax controls timing.

Conclusion

GitHub Actions makes CI/CD accessible with everything defined in YAML in your repo. This guide covers the essentials — CI workflows with matrix builds, dependency caching, Docker image building, and deployment with environment approvals. The huge marketplace of pre-built actions means you rarely write things from scratch. Start with a simple test workflow, add build and deploy jobs incrementally, cache aggressively for speed, and use environments to gate production deployments. It’s the fastest path to professional CI/CD for GitHub-hosted projects.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা