πŸ“‹ Cheat Sheets

GitHub Actions Cheat Sheet β€” Workflow Syntax and Common Patterns


Click any item to expand the explanation and examples.

πŸ”§ Workflow Structure

Minimal workflow basics
# .github/workflows/ci.yml
name: CI

on: push

jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: echo β€œHello World”

Every workflow needs: on (trigger), jobs (what to run), steps (individual commands).

🎯 Triggers (on:)

Push & pull request trigger
# On push to specific branches
on:
  push:
    branches: [main, develop]
    paths:
      - 'src/**'
      - '!src/**/*.test.ts'   # Ignore test files

On pull request

on: pull_request: branches: [main] types: [opened, synchronize, reopened]

Both

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

Schedule (cron) trigger
on:
  schedule:
    - cron: '0 6 * * *'    # Daily at 6am UTC
    - cron: '0 */4 * * *'  # Every 4 hours
    - cron: '0 9 * * 1'    # Monday at 9am UTC

Cron format: minute hour day-of-month month day-of-week

β”Œβ”€β”€β”€β”€β”€ minute (0-59)

β”‚ β”Œβ”€β”€β”€β”€β”€ hour (0-23)

β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€ day of month (1-31)

β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€ month (1-12)

β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€ day of week (0-6, Sun=0)

* * * * *

Manual, release, and other triggers trigger
# Manual trigger with inputs
on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deploy to'
        required: true
        default: 'staging'
        type: choice
        options: [staging, production]

On release published

on: release: types: [published]

On issue comment

on: issue_comment: types: [created]

βš™οΈ Jobs & Steps

Job configuration jobs
jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 10
# Job-level environment variables
env:
  NODE_ENV: test

steps:
  - uses: actions/checkout@v4
  - uses: actions/setup-node@v4
    with:
      node-version: 20
  - run: npm ci
  - run: npm test

deploy: runs-on: ubuntu-latest needs: test # Run after test job if: github.ref == β€˜refs/heads/main’ environment: production # Requires approval steps: - uses: actions/checkout@v4 - run: ./deploy.sh

Matrix strategy jobs
Run the same job with different configurations.
jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        node: [18, 20, 22]
      fail-fast: false  # Don't cancel other jobs if one fails
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci
      - run: npm test
This creates 9 jobs (3 OS Γ— 3 Node versions).
Step outputs & conditionals jobs
steps:
  - name: Get version
    id: version
    run: echo "tag=$(git describe --tags)" >> $GITHUB_OUTPUT
  • name: Use the output run: echo β€œVersion is ${{ steps.version.outputs.tag }}”

  • name: Only on main if: github.ref == β€˜refs/heads/main’ run: echo β€œOn main branch”

  • name: Only on failure if: failure() run: echo β€œSomething failed”

  • name: Always run (cleanup) if: always() run: echo β€œCleanup”

πŸ” Secrets & Variables

Using secrets secrets
# Set in: Settings β†’ Secrets and variables β†’ Actions

steps:

  • name: Deploy env: API_KEY: ${{ secrets.API_KEY }} run: ./deploy.sh

  • name: Docker login run: echo ”${{ secrets.DOCKER_PASSWORD }}” | docker login -u ”${{ secrets.DOCKER_USERNAME }}” β€”password-stdin

Secrets are masked in logs. Never echo them directly.

Built-in variables vars
# Common github context variables
${{ github.ref }}              # refs/heads/main
${{ github.sha }}              # Full commit SHA
${{ github.actor }}            # User who triggered
${{ github.repository }}       # owner/repo
${{ github.event_name }}       # push, pull_request, etc.
${{ github.run_number }}       # Incrementing run number
${{ github.workspace }}        # Workspace path

PR-specific

${{ github.event.pull_request.number }} ${{ github.event.pull_request.head.ref }} ${{ github.base_ref }}

πŸ“¦ Caching & Artifacts

Cache dependencies cache
# Node.js (built into setup-node)
- uses: actions/setup-node@v4
  with:
    node-version: 20
    cache: 'npm'

Manual cache

  • uses: actions/cache@v4 with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles(’**/package-lock.json’) }} restore-keys: | ${{ runner.os }}-npm-
Upload & download artifacts artifacts
# Upload build output
- uses: actions/upload-artifact@v4
  with:
    name: build
    path: dist/

Download in another job

deploy: needs: build steps: - uses: actions/download-artifact@v4 with: name: build path: dist/

πŸš€ Common Workflows

Node.js CI recipe
name: CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs: ci: 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 run build - run: npm test

Deploy to Vercel recipe
name: Deploy
on:
  push:
    branches: [main]

jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - 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’