Click any item to expand the explanation and examples.
π§ Workflow Structure
Minimal workflow basics
# .github/workflows/ci.yml name: CIEvery workflow needs:on: push
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: echo βHello Worldβ
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
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 β Actionssteps:
-
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
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β