GitHub Actions Cheatsheet
Workflow Syntax
Use this GitHub Actions reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Top-Level Keys
| Key | Required | Description |
|---|---|---|
name | no | Display name in the Actions UI |
on | yes | Event(s) that trigger the workflow |
env | no | Workflow-level environment variables |
defaults | no | Default run shell and working directory |
concurrency | no | Cancel or queue duplicate runs |
permissions | no | GITHUB_TOKEN permission overrides |
jobs | yes | Map of job IDs to job definitions |
on — Trigger Syntax
# Single event on: push # Multiple events on: [push, pull_request] # Event with filters on: push: branches: [main, 'release/**'] branches-ignore: ['dependabot/**'] tags: ['v*'] paths: ['src/**', '!src/**/*.test.ts'] pull_request: types: [opened, synchronize, reopened] schedule: - cron: '0 6 * * 1-5' workflow_dispatch: inputs: environment: description: 'Target environment' required: true default: staging type: choice options: [staging, production]
env — Environment Variables
# Workflow level env: NODE_ENV: test API_URL: https://api.example.com jobs: build: # Job level (merges with workflow env) env: LOG_LEVEL: debug steps: - run: echo "NODE_ENV=$NODE_ENV" # Step level (highest precedence) env: NODE_ENV: production
defaults
defaults:
run:
shell: bash
working-directory: ./appPer-job override:
jobs:
build:
defaults:
run:
working-directory: ./packages/coreconcurrency
# Cancel in-progress runs for the same branch concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true # Queue instead of cancel (omit cancel-in-progress or set false) concurrency: group: deploy-production cancel-in-progress: false
jobs — Job Keys
| Key | Required | Description |
|---|---|---|
runs-on | yes | Runner label(s) |
steps | yes* | Ordered list of steps (*or uses for reusable workflows) |
needs | no | Job dependencies (run after these job IDs) |
if | no | Conditional expression |
env | no | Job-level env vars |
outputs | no | Values passed to dependent jobs |
strategy | no | Matrix / fail-fast config |
timeout-minutes | no | Job timeout (default 360) |
continue-on-error | no | true = don't fail workflow if job fails |
services | no | Docker service containers |
container | no | Run all steps inside a container |
permissions | no | Per-job GITHUB_TOKEN scopes |
environment | no | Deployment environment (gates, URLs) |
concurrency | no | Job-level concurrency group |
steps — Step Keys
| Key | Description |
|---|---|
name | Display label |
id | Reference in steps.<id>.outputs |
uses | Action reference (owner/repo@ref) |
run | Shell command(s) |
with | Input parameters for uses |
env | Step-level env vars |
if | Conditional |
continue-on-error | Allow step failure without failing job |
timeout-minutes | Step timeout |
working-directory | Override working dir for run |
shell | Override shell for run |
Expressions
# Syntax: ${{ <expression> }} if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} # Functions ${{ contains(github.event.head_commit.message, '[skip ci]') }} ${{ startsWith(github.ref, 'refs/tags/v') }} ${{ toJSON(matrix) }} ${{ fromJSON(steps.meta.outputs.json).version }} ${{ format('Hello {0}', github.actor) }} ${{ join(matrix.os, ', ') }} # Status functions (use in if: without ${{ }}) if: success() if: failure() if: always() if: cancelled() if: failure() && steps.build.conclusion == 'failure'
Outputs
jobs:
build:
outputs:
version: ${{ steps.get-version.outputs.version }}
steps:
- id: get-version
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
deploy:
needs: build
steps:
- run: echo "Deploying ${{ needs.build.outputs.version }}"Multi-line run
- run: |
echo "Line 1"
echo "Line 2"
npm ci
npm testSetting Output / Env from a Step
# Set output echo "my-key=my-value" >> $GITHUB_OUTPUT # Set env var for subsequent steps echo "MY_VAR=hello" >> $GITHUB_ENV # Add to PATH echo "/custom/bin" >> $GITHUB_PATH # Step summary (rendered Markdown in the UI) echo "## Build Summary" >> $GITHUB_STEP_SUMMARY echo "| Key | Value |" >> $GITHUB_STEP_SUMMARY
services — Docker Sidecars
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- run: psql -h localhost -U postgres -c '\l'
env:
PGPASSWORD: postgres