Stackbook Logo
← Back to Tools

GitHub Actions for CI/CD

Build CI/CD pipelines with GitHub Actions: workflows, jobs, caching, secrets, OIDC cloud authentication, reusable workflows and common pitfalls.

4 min read

What it is and when to use it

GitHub Actions is the automation platform built into GitHub. A workflow is a YAML file in your repository that runs jobs on hosted or self-hosted runners in response to events such as pushes, pull requests, schedules or manual triggers. It covers continuous integration, container builds, infrastructure plans and continuous deployment.

Use it when your code already lives on GitHub and you want pipelines versioned beside the code, with a large marketplace of reusable actions.

Quick start

Create the file .github/workflows/ci.yml.

name: CI
on:
  push:
    branches: [main]
  pull_request:

permissions:
  contents: read

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

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 test

Commit and push; the run appears under the Actions tab. You can also use the GitHub CLI.

gh workflow list
gh run list --limit 5
gh run watch
gh run view --log-failed
gh workflow run deploy.yml -f environment=staging

Core concepts

Events trigger workflows: push, pull_request, schedule with a cron expression, workflow_dispatch for manual runs, release, and workflow_call for reuse.

Jobs run in parallel by default, each on a fresh runner. Use needs to create ordering, and pass data with outputs or artifacts.

Steps run shell commands with run, or call an action with uses. Pin third-party actions to a full commit SHA for supply chain safety.

Matrix builds fan one job across versions or platforms.

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 test

Secrets and variables are set in repository or organization settings and read as secrets.NAME or vars.NAME. They are masked in logs. Environments add protection rules such as required reviewers before a deploy job runs.

Artifacts and caching. Use actions/upload-artifact to hand files between jobs, and caching built into setup actions, or actions/cache, to speed up dependency installs.

OIDC to the cloud. Instead of storing long-lived cloud keys, let the workflow exchange a short-lived token.

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/gha-deploy
          aws-region: eu-west-1
      - run: aws s3 sync ./dist s3://my-site-bucket

Reusable workflows let teams centralize pipelines. A caller invokes one with uses pointing at a path in another repo, and the callee declares on workflow_call with typed inputs and secrets.

Docker image build and push is typically done with the docker/login-action, docker/setup-buildx-action and docker/build-push-action trio, authenticating to ghcr.io with the built-in GITHUB_TOKEN.

Pitfalls

  • Leave permissions at the minimum. Set read-only at the top and grant write only to jobs that need it.
  • Never use pull_request_target with a checkout of untrusted pull request code; it runs with secrets and is a known attack path.
  • Injecting untrusted values such as issue titles or branch names directly into run scripts allows command injection. Pass them through env variables instead.
  • Secrets are not available to workflows triggered from forks by default, so tests that need them will fail on outside contributions.
  • Unpinned actions can change under you. Pin to SHAs and let Dependabot update them.
  • Hosted runner minutes cost money on private repos. Use concurrency cancellation, path filters and caching.
  • Cron schedules run in UTC and can be delayed under load.
  • YAML gotchas: the key on can be misread by some linters, and expressions that begin with a dollar sign and braces must be quoted inside certain values.

How it fits an architecture

GitHub Actions is the integration point of a delivery pipeline. On pull requests it lints, tests and runs Terraform plan. On merge it builds an image, scans it, pushes it to a registry, and updates the config repository so Argo CD deploys it, or it calls helm upgrade directly. Scheduled workflows handle drift detection and dependency audits. Environments with approvals add a manual gate before production.

Key takeaways

  • Workflows are YAML files under .github/workflows triggered by events.
  • Prefer OIDC federation to stored cloud credentials.
  • Pin actions, restrict permissions and treat untrusted input as hostile.
  • Use matrices, caching and concurrency to keep pipelines fast and cheap.
  • Extract shared logic into reusable workflows for consistency across repos.