GitHub Actions Complete Guide 2026 — CI/CD Pipelines, Workflows, and Automation
Advertisement
Introduction
Why This Matters
GitHub Actions is the most widely used CI/CD platform in 2026 — free for public repos, deeply integrated with GitHub, and powerful enough to replace standalone tools like Jenkins or CircleCI. Every push, PR, or schedule can trigger automated testing, building, and deployment. Teams that automate their pipeline ship faster with fewer bugs reaching production.
Core Concepts
A GitHub Actions workflow is a YAML file stored in .github/workflows/. Key terms:
| Term | Definition |
|---|---|
| Workflow | The YAML file defining the automation |
| Event | What triggers the workflow (push, PR, schedule) |
| Job | A set of steps on one runner |
| Step | Individual task — run a command or use an action |
| Runner | The VM where jobs execute |
| Action | Reusable step from the Marketplace |
Full CI/CD Pipeline for Next.js
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
NODE_VERSION: '20'
jobs:
test:
name: Test
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: testdb
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run typecheck
- name: Run tests with coverage
run: npm run test:coverage
env:
DATABASE_URL: postgresql://test:test@localhost:5432/testdb
- uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
deploy:
name: Deploy
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
steps:
- uses: actions/checkout@v4
- name: Deploy to Vercel
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'Docker Build and Push to GitHub Container Registry
# .github/workflows/docker.yml
name: Build and Push Docker Image
on:
push:
branches: [main]
tags: ['v*']
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha,prefix=sha-
- uses: docker/setup-buildx-action@v3
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64Matrix Builds and Caching
Test across multiple Node.js versions and operating systems in parallel:
jobs:
test:
strategy:
fail-fast: false
matrix:
node: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci && npm testSpeed up builds with dependency caching:
- name: Cache npm dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: npm-${{ runner.os }}-
- name: Cache Next.js build
uses: actions/cache@v4
with:
path: .next/cache
key: nextjs-${{ runner.os }}-${{ hashFiles('**/*.ts', '**/*.tsx') }}Reusable Workflows and Secrets
Define once, call from many workflows:
# .github/workflows/reusable-deploy.yml
on:
workflow_call:
inputs:
environment:
required: true
type: string
secrets:
DEPLOY_TOKEN:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- name: Deploy to ${{ inputs.environment }}
run: echo "Deploying..."
env:
TOKEN: ${{ secrets.DEPLOY_TOKEN }}Call the reusable workflow from another file:
jobs:
deploy-staging:
uses: ./.github/workflows/reusable-deploy.yml
with:
environment: staging
secrets:
DEPLOY_TOKEN: ${{ secrets.STAGING_TOKEN }}Common Mistakes
- Storing secrets in workflow YAML — always use
${{ secrets.NAME }}, never hardcode values - Not pinning action versions — use
@v4or a specific commit SHA to avoid supply-chain attacks - Missing
needsbetween jobs — without it, jobs run in parallel and may deploy before tests pass - No caching — npm install on every run wastes 60-90 seconds per job
- Running expensive jobs on every PR — use
if:conditions to limit deploy jobs to the main branch only
Best Practices
- Use
concurrencygroups to cancel in-progress runs when a new push arrives - Store all sensitive values in GitHub Secrets or Environments, never in env files committed to the repo
- Use
workflow_dispatchto allow manual re-runs without a new commit - Set
timeout-minuteson every job to prevent runaway builds from consuming free minutes - Use
permissions:at the workflow level to follow least-privilege principle
# Concurrency example — cancel old runs on same branch
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: trueKey Takeaways
- GitHub Actions workflows live in
.github/workflows/as YAML files and trigger on events likepush,pull_request, orschedule - Jobs within a workflow run in parallel by default; use
needs:to enforce sequential execution - Use
matrixstrategy to test across multiple Node.js versions and OS combinations in one workflow definition - Action caching with
actions/cache@v4can cut build times by 60-90% by reusingnode_modulesand build artifacts - Reusable workflows (
workflow_call) let you define deploy logic once and call it from multiple pipelines - Always scope
permissions:to the minimum required — default isread-allfor security - Use
concurrencygroups to automatically cancel stale workflow runs when new commits are pushed - GitHub Environments add required reviewers and secret scoping for production deployments
Advertisement
Related reading
GitHub Actions — Complete CI/CD Guide 20266 min readGitHub Actions vs Jenkins vs GitLab CI — CI/CD Comparison 20267 min readGitHub Actions for Node.js — Complete CI/CD Pipeline Guide 20265 min readGitHub Actions for Docker — Build, Tag, and Push Images 20265 min readGitLab CI/CD — Complete Pipeline Guide for 20265 min readJenkins Pipeline — Declarative CI/CD Syntax Complete Guide4 min read