env.dev

GitHub Actions Cheat Sheet

Quick reference for GitHub Actions CI/CD: workflow syntax, triggers, jobs, matrix strategies, secrets, caching, artifacts, reusable workflows, and essential actions.

Last updated:

GitHub Actions quick-reference covering workflow syntax, triggers, job configuration, expressions, matrix strategies, secrets, caching, artifacts, and reusable workflows. Organized by task for fast lookup when building CI/CD pipelines.

Workflow File Structure

KeyDescription
.github/workflows/*.ymlWorkflow files must live in this directory
name:Display name shown in the Actions tab
on:Event triggers that start the workflow
permissions:GITHUB_TOKEN permissions for the workflow
env:Environment variables available to all jobs
concurrency:Prevent concurrent runs (e.g. deploy to same environment)
jobs:Map of job IDs to job configurations

How Do You Trigger a Workflow?

TriggerDescription
on: pushRun on every push to any branch
on: push: branches: [main]Run only on pushes to main
on: pull_requestRun on PR open, synchronize, reopen
on: pull_request: types: [opened, labeled]Run on specific PR activity types
on: schedule: - cron: "0 6 * * 1"Run on a cron schedule (Mondays at 06:00 UTC)
on: workflow_dispatchEnable manual trigger via the Actions UI
on: workflow_dispatch: inputs:Manual trigger with user-provided inputs
on: workflow_callMake this workflow callable by other workflows
on: release: types: [published]Run when a release is published
on: push: paths: ["src/**"]Run only when files in src/ change
on: push: paths-ignore: ["docs/**"]Skip when only docs/ files change

Job Configuration

KeyDescription
runs-on: ubuntu-latestRun on the latest Ubuntu runner
runs-on: [self-hosted, linux]Run on a self-hosted runner with matching labels
needs: [build, test]Run after the listed jobs complete successfully
if: success()Conditional execution (also: failure(), always(), cancelled())
timeout-minutes: 30Cancel the job after 30 minutes
continue-on-error: trueAllow the workflow to pass even if this job fails
environment: productionLink to a deployment environment with protection rules
services:Spin up sidecar containers (e.g. postgres, redis) for the job
container: node:20Run all steps inside a Docker container

Step Syntax

KeyDescription
- uses: actions/checkout@v4Use a published action (org/repo@ref)
- run: npm testRun a shell command
- run: |Run a multi-line script (YAML block scalar)
name: "Run tests"Display name for the step
id: my-stepID to reference outputs via steps.my-step.outputs.*
if: github.ref == 'refs/heads/main'Conditional step execution
with:Input parameters for the action
env:Environment variables scoped to this step
working-directory: ./appSet the working directory for run commands
shell: bashSpecify the shell (bash, pwsh, python, sh)

Expressions & Contexts

ExpressionDescription
${{ github.sha }}Full SHA of the commit that triggered the run
${{ github.ref_name }}Branch or tag name (e.g. main, v1.0.0)
${{ github.event_name }}Event that triggered the workflow (push, pull_request, etc.)
${{ github.actor }}Username that triggered the workflow
${{ github.repository }}Owner/repo (e.g. octocat/hello-world)
${{ secrets.MY_SECRET }}Access a repository or organization secret
${{ vars.MY_VAR }}Access a configuration variable
${{ env.MY_VAR }}Access an environment variable
${{ steps.<id>.outputs.<key> }}Output from a previous step
${{ needs.<job>.outputs.<key> }}Output from a dependency job
${{ runner.os }}Runner OS: Linux, Windows, or macOS
${{ toJSON(github) }}Convert a context to JSON (useful for debugging)

Matrix Strategy

KeyDescription
strategy: matrix:Define variables that create parallel job combinations
matrix: { node: [18, 20, 22] }Run the job once for each value
matrix: { os: [ubuntu-latest, windows-latest] }Test across operating systems
fail-fast: falseContinue other matrix jobs even if one fails
max-parallel: 2Limit concurrent matrix jobs
include: [{ node: 22, experimental: true }]Add extra combinations to the matrix
exclude: [{ os: windows-latest, node: 18 }]Remove specific combinations
${{ matrix.node }}Reference the current matrix value in steps

Secrets, Variables & Permissions

PatternDescription
${{ secrets.GITHUB_TOKEN }}Auto-generated token scoped to the repo
${{ secrets.MY_SECRET }}Custom secret set in repo or org settings
${{ vars.DEPLOY_ENV }}Configuration variable (non-sensitive)
permissions: contents: readLimit GITHUB_TOKEN to read-only for contents
permissions: pull-requests: writeAllow the workflow to comment on PRs
permissions: packages: writeAllow publishing to GitHub Packages
permissions: id-token: writeEnable OIDC for cloud provider authentication

Caching & Artifacts

PatternDescription
actions/cache@v4Cache dependencies between workflow runs
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}Cache key based on lockfile hash
restore-keys: ${{ runner.os }}-node-Fallback cache key prefix
actions/upload-artifact@v4Upload build output or test results
actions/download-artifact@v4Download artifact in a later job
retention-days: 5Auto-delete artifacts after 5 days
actions/setup-node@v4 with: cache: pnpmBuilt-in caching for Node.js (npm, yarn, pnpm)

Reusable Workflows & Composite Actions

PatternDescription
on: workflow_call:Define a reusable workflow that other workflows can call
workflow_call: inputs:Declare input parameters for the reusable workflow
workflow_call: secrets:Declare secrets the caller must pass
uses: ./.github/workflows/deploy.ymlCall a reusable workflow in the same repo
uses: org/repo/.github/workflows/ci.yml@mainCall a reusable workflow from another repo
with:Pass inputs to the called workflow
secrets: inheritPass all secrets from caller to called workflow
action.yml with runs: compositeDefine a composite action bundling multiple steps

Essential Actions

ActionDescription
actions/checkout@v4Check out repository code
actions/setup-node@v4Install Node.js and optionally cache dependencies
actions/setup-python@v5Install Python and optionally cache pip/pipenv
actions/setup-go@v5Install Go and cache modules
actions/cache@v4Cache files between workflow runs
actions/upload-artifact@v4Upload artifacts from a job
actions/download-artifact@v4Download artifacts in a later job
actions/github-script@v7Run JavaScript with the GitHub API (Octokit)
docker/build-push-action@v6Build and push Docker images
aws-actions/configure-aws-credentials@v4Authenticate to AWS via OIDC or access keys

Frequently Asked Questions

How do you pass data between jobs in GitHub Actions?

Use job outputs. In the producing job, set an output with echo "key=value" >> $GITHUB_OUTPUT in a step with an id, then declare it under jobs.<job>.outputs. The consuming job references it via needs.<job>.outputs.<key>. For files, use upload-artifact and download-artifact.

What is the difference between secrets and variables in GitHub Actions?

Secrets (${{ secrets.X }}) are encrypted, never printed in logs, and meant for tokens, passwords, and keys. Variables (${{ vars.X }}) are plaintext configuration values like environment names or feature flags. Both can be set at the repository, environment, or organization level.

How do you run a job only on the main branch?

Add a conditional: if: github.ref == 'refs/heads/main' at the job level or step level. Alternatively, scope the trigger itself: on: push: branches: [main]. The trigger approach prevents the entire workflow from running, while the if conditional skips only that job.

How do you debug a failing GitHub Actions workflow?

Enable debug logging by setting the repository secret ACTIONS_STEP_DEBUG to true. Use ${{ toJSON(github) }} to dump context. Add run: env to print all environment variables. For interactive debugging, use mxschmitt/action-tmate to SSH into the runner.

What is the difference between uses and run in a step?

uses references a published action (a reusable unit of code from the GitHub Marketplace or another repo), while run executes a shell command directly. You cannot combine both in the same step — each step is either uses or run.

How do reusable workflows differ from composite actions?

Reusable workflows are full workflows called with workflow_call — they run as separate workflow runs and can contain multiple jobs. Composite actions are single actions defined in action.yml that bundle multiple steps into one reusable unit. Use reusable workflows for full CI/CD pipelines and composite actions for shared step sequences.