📖 Guide
GitHub Actions — Complete Reference
Complete GitHub Actions cheat sheet — workflows, triggers, jobs, and CI/CD patterns.
76 commands across 10 categories
Workflow BasicsTriggersJobs & StepsEnvironment VariablesSecretsMatrix StrategyCachingArtifactsCommon ActionsExpressions & Contexts
Workflow Basics
| Command | Description |
|---|---|
.github/workflows/ci.yml | Workflow files live in .github/workflows/ directory |
name: CI Pipeline | Set the workflow display name |
on: push | Trigger workflow on push events |
runs-on: ubuntu-latest | Specify the runner OS (ubuntu-latest, windows-latest, macos-latest) |
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 | Minimal workflow structure |
concurrency:
group: ci-main
cancel-in-progress: true | Cancel redundant runs for the same group |
permissions:
contents: read
packages: write | Set GITHUB_TOKEN permissions for the workflow |
Triggers
| Command | Description |
|---|---|
on:
push:
branches: [main, develop] | Trigger on push to specific branches |
on:
pull_request:
types: [opened, synchronize] | Trigger on PR events |
on:
push:
paths:
- "src/**"
- "!docs/**" | Trigger only when specific paths change (with exclusion) |
on:
schedule:
- cron: "0 6 * * 1" | Scheduled trigger (every Monday at 06:00 UTC) |
on:
workflow_dispatch:
inputs:
environment:
type: choice
options: [staging, production] | Manual trigger with input parameters |
on:
release:
types: [published] | Trigger on new release publication |
on:
workflow_call:
inputs:
node-version:
type: string
required: true | Make workflow reusable (callable from other workflows) |
on:
push:
tags:
- "v*" | Trigger on version tags |
Jobs & Steps
| Command | Description |
|---|---|
steps:
- uses: actions/checkout@v4 | Check out the repository code |
- name: Install deps
run: npm ci | Run a shell command |
- name: Multi-line script
run: |
echo "Line 1"
echo "Line 2" | Multi-line shell commands |
needs: [build, lint] | Job dependency — wait for other jobs to finish |
if: github.ref == 'refs/heads/main' | Conditional job/step execution |
- name: Upload
if: success()
run: echo "Only on success" | Run step only if previous steps succeeded (also: failure(), always(), cancelled()) |
timeout-minutes: 15 | Set timeout for a job |
continue-on-error: true | Allow a step to fail without failing the job |
working-directory: ./frontend | Set working directory for a step's run commands |
services:
postgres:
image: postgres:15
ports:
- 5432:5432 | Run service containers alongside the job |
Environment Variables
| Command | Description |
|---|---|
env:
NODE_ENV: production | Set env vars at workflow, job, or step level |
GITHUB_SHA | Built-in: the commit SHA that triggered the workflow |
GITHUB_REF | Built-in: the branch or tag ref (e.g. refs/heads/main) |
GITHUB_REPOSITORY | Built-in: owner/repo name |
GITHUB_ACTOR | Built-in: username that triggered the workflow |
GITHUB_RUN_NUMBER | Built-in: sequential number for each workflow run |
echo "MY_VAR=value" >> "$GITHUB_ENV" | Set environment variable for subsequent steps |
echo "result=success" >> "$GITHUB_OUTPUT" | Set step output for use in other steps |
Secrets
| Command | Description |
|---|---|
secrets.GITHUB_TOKEN | Auto-generated token with repo permissions |
secrets.MY_SECRET | Access a repository or organization secret |
env:
API_KEY: ${{ secrets.API_KEY }}e.g. Use single quotes around the expression in YAML | Pass secret as environment variable |
vars.MY_VARIABLE | Access a repository configuration variable (non-secret) |
environment: production | Use environment-specific secrets by specifying an environment |
secrets.inherite.g. jobs:
call:
uses: ./.github/workflows/reusable.yml
secrets: inherit | Pass all secrets to a called reusable workflow |
Matrix Strategy
| Command | Description |
|---|---|
strategy:
matrix:
node-version: [18, 20, 22] | Run job across multiple configurations |
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }} | Use matrix value in a step |
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
node: [18, 20]e.g. runs-on: ${{ matrix.os }} | Multi-dimensional matrix (creates all combinations) |
include:
- os: ubuntu-latest
node: 22
experimental: true | Add specific combinations to the matrix |
exclude:
- os: windows-latest
node: 18 | Exclude specific combinations from the matrix |
strategy:
fail-fast: false | Continue other matrix jobs even if one fails |
strategy:
max-parallel: 2 | Limit concurrent matrix jobs |
Caching
| Command | Description |
|---|---|
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ hashFiles('**/package-lock.json') }} | Cache npm dependencies |
restore-keys: |
npm-${{ runner.os }}- | Fallback cache keys when exact match not found |
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm | Built-in caching with setup-node (simplest) |
- uses: actions/cache@v4
with:
path: |
~/.cache/pip
~/.local
key: pip-${{ hashFiles('**/requirements.txt') }} | Cache multiple directories |
- uses: actions/cache/restore@v4
with:
path: ./dist
key: build-${{ github.sha }} | Restore cache without saving (read-only) |
- uses: actions/cache/save@v4
if: always()
with:
path: ./dist
key: build-${{ github.sha }} | Save cache even if job fails |
Artifacts
| Command | Description |
|---|---|
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/ | Upload build artifacts |
- uses: actions/download-artifact@v4
with:
name: build-output | Download artifacts in a later job |
retention-days: 5 | Set artifact retention period |
if-no-files-found: error | Fail if no files match the path (warn, ignore, error) |
path: |
dist/
coverage/
!dist/**/*.map | Upload multiple paths with exclusions |
- uses: actions/download-artifact@v4
with:
name: build-output
path: ./downloaded | Download artifact to a specific directory |
Common Actions
| Command | Description |
|---|---|
uses: actions/checkout@v4 | Check out repository (most used action) |
uses: actions/setup-node@v4
with:
node-version: 20 | Set up Node.js environment |
uses: actions/setup-python@v5
with:
python-version: "3.12" | Set up Python environment |
uses: docker/build-push-action@v5
with:
push: true
tags: user/app:latest | Build and push Docker image |
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} | Log in to container registry |
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist | Deploy to GitHub Pages |
uses: softprops/action-gh-release@v1
with:
files: dist/*.zip | Create GitHub Release with assets |
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({ ... }) | Run JavaScript with GitHub API access |
Expressions & Contexts
| Command | Description |
|---|---|
github.event_name | The event that triggered the workflow (push, pull_request, etc.) |
github.event.pull_request.number | PR number from the event payload |
runner.os | The OS of the runner (Linux, Windows, macOS) |
steps.step_id.outputs.result | Access output from a previous step by its id |
needs.job_id.outputs.my_output | Access output from a dependent job |
contains(github.event.head_commit.message, '[skip ci]') | Check if commit message contains a string |
startsWith(github.ref, 'refs/tags/v') | Check if ref starts with a value |
toJSON(github.event) | Convert context to JSON string (useful for debugging) |
hashFiles('**/package-lock.json') | Generate hash of files (used for cache keys) |
format('Hello {0}, from {1}!', 'world', 'GHA') | String formatting function |
📖 Free, searchable command reference. Bookmark this page for quick access.