cluster deboistech.in Get started
Cheatsheet

CI/CD with GitHub Actions

Workflow files for GitHub Actions: triggers, jobs, steps, secrets, caching, matrices and reuse.

Practice this path

A workflow file

Save it as .github/workflows/ci.yml.

  • name: CI
    on:
      push:
        branches: [main]
      pull_request:
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - run: npm ci && npm test

    The smallest useful pipeline: test on every push and pull request

  • permissions:
      contents: read

    Give the workflow only the access it needs

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

    Cancel an older run of the same branch when a new one starts

Triggers

  • on: [push, pull_request]

    On pushes and pull requests

  • on:
      schedule:
        - cron: "0 6 * * 1"

    On a schedule (UTC): Mondays at 06:00

  • on:
      workflow_dispatch:
        inputs:
          env: { type: choice, options: [staging, prod] }

    A manual "Run workflow" button with an input

  • on:
      push:
        paths: ["src/**"]
        tags: ["v*"]

    Only for some paths, or for version tags

  • on:
      workflow_call:

    Make this workflow reusable by other workflows

Jobs and steps

  • needs: [build, test]

    Run a job only after others succeed

  • if: github.ref == 'refs/heads/main'

    Run a job or step only in some cases

  • strategy:
      matrix:
        node: [18, 20, 22]
    steps:
      - uses: actions/setup-node@v4
        with: { node-version: "${{ matrix.node }}" }

    The same job on several versions at once

  • timeout-minutes: 15

    Stop a job that hangs

  • continue-on-error: true

    Do not fail the workflow if this step fails

  • defaults:
      run:
        working-directory: app

    Set the folder for every run step

  • - name: Show the context
      run: echo "$GITHUB_SHA on $GITHUB_REF_NAME"

    Built-in environment variables

Secrets, variables and outputs

  • env:
      API_KEY: ${{ secrets.API_KEY }}

    Use a repository secret (it is masked in logs)

  • ${{ vars.REGION }}

    A non-secret configuration variable

  • echo "version=1.2.3" >> "$GITHUB_OUTPUT"

    Set a step output; read it as ${{ steps.<id>.outputs.version }}

  • echo "$HOME/bin" >> "$GITHUB_PATH"

    Add a folder to PATH for the next steps

  • environment: production

    Use an environment: its secrets and required approvals

  • permissions:
      id-token: write
      contents: read

    Allow OIDC login to a cloud provider, with no stored cloud keys

Caching and artifacts

  • - uses: actions/setup-node@v4
      with: { node-version: 20, cache: npm }

    Cache the npm download folder

  • - uses: actions/cache@v4
      with:
        path: ~/.cache/pip
        key: pip-${{ hashFiles('requirements.txt') }}

    Cache anything, keyed on a file's hash

  • - uses: actions/upload-artifact@v4
      with: { name: report, path: report/ }

    Keep files from a run

  • - uses: actions/download-artifact@v4
      with: { name: report }

    Use them in a later job

Build and ship

  • - uses: docker/build-push-action@v6
      with:
        push: true
        tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

    Build and push a container image

  • jobs:
      call:
        uses: org/repo/.github/workflows/deploy.yml@main
        with: { env: staging }
        secrets: inherit

    Call a reusable workflow

  • - run: gh release create "$GITHUB_REF_NAME" --generate-notes
      env: { GH_TOKEN: "${{ github.token }}" }

    Create a release from a tag

  • actions/checkout@<full commit SHA>

    Pin third-party actions to a commit, not a moving tag

Cheatsheet for the CI/CD with GitHub Actions path · Deboistech · All cheatsheets