Workflow Basics
Minimal Workflow
# .github/workflows/ci.yml name: CI on: push jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: echo "Hello from CI"
Key Concepts
WorkflowYAML file in .github/workflows/ that defines automation
EventTrigger that starts a workflow (push, PR, schedule, etc.)
JobSet of steps that run on the same runner
StepIndividual task — runs a command or uses an action
RunnerVM that executes jobs (ubuntu-latest, macos-latest, windows-latest)
ActionReusable unit of code referenced with uses:
Triggers
Common Events
on: push: branches: [main] pull_request: branches: [main] schedule: - cron: "0 6 * * 1" # every Monday 6 AM UTC workflow_dispatch: # manual trigger
Event Filters
branches:Trigger only for specific branches
paths:Trigger only when matching files change
tags:Trigger on tag pushes (v*)
types: [opened, synchronize]Filter PR activity types
branches-ignore:Exclude specific branches
paths-ignore:Exclude specific file paths
Jobs & Steps
Job Configuration
jobs: test: runs-on: ubuntu-latest needs: build # depends on build job if: github.ref == 'refs/heads/main' timeout-minutes: 10 steps: - uses: actions/checkout@v4 - run: npm test
Step Types
run:Execute a shell command
uses:Use a published action
with:Pass inputs to an action
name:Display name in the UI
id:Reference step outputs via steps..outputs
if:Conditional execution
continue-on-error: trueDon't fail the job if step fails
Actions
Using Actions
steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - uses: ./.github/actions/my-action # local action
Popular Actions
actions/checkout@v4Check out repository code
actions/setup-node@v4Install Node.js
actions/setup-python@v5Install Python
actions/upload-artifact@v4Upload build artifacts
actions/download-artifact@v4Download artifacts from another job
actions/cache@v4Cache dependencies between runs
actions/github-script@v7Run JS with the GitHub API client
Environment Variables
Setting Variables
env: # workflow-level NODE_ENV: production jobs: build: env: # job-level CI: true steps: - run: echo "$MY_VAR" env: # step-level MY_VAR: hello
Default Variables
github.shaCommit SHA that triggered the workflow
github.refBranch or tag ref (refs/heads/main)
github.repositoryOwner/repo name
github.actorUser who triggered the workflow
github.event_nameEvent that triggered the workflow
runner.osRunner OS (Linux, macOS, Windows)
Secrets
Using Secrets
steps: - run: deploy --token "$TOKEN" env: TOKEN: ${{ secrets.DEPLOY_TOKEN }} - uses: some/action@v1 with: api-key: ${{ secrets.API_KEY }}
Secret Rules
secrets.GITHUB_TOKENAuto-generated token scoped to the repo
Settings → SecretsAdd secrets in repo or org settings
MaskingSecret values are masked in logs automatically
Environment secretsScoped to a deployment environment
Org secretsShared across repos in an organization
Matrix Strategy
Matrix Builds
jobs: test: strategy: matrix: os: [ubuntu-latest, macos-latest] node: [18, 20] runs-on: ${{ matrix.os }} steps: - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }}
Matrix Options
matrix:Define variable combinations to expand
include:Add extra combinations to the matrix
exclude:Remove specific combinations
fail-fast: falseContinue other jobs if one fails
max-parallel: 2Limit concurrent matrix jobs
Caching
Cache Dependencies
- uses: actions/cache@v4 with: path: ~/.npm key: npm-${{ hashFiles('package-lock.json') }} restore-keys: npm-
Built-in Caching
- uses: actions/setup-node@v4 with: node-version: 20 cache: npm # auto-cache for npm/yarn/pnpm - uses: actions/setup-python@v5 with: python-version: "3.12" cache: pip # auto-cache for pip
Artifacts
Upload & Download
- uses: actions/upload-artifact@v4 with: name: build-output path: dist/ retention-days: 7 - uses: actions/download-artifact@v4 with: name: build-output
Artifact Notes
retention-daysAuto-delete after N days (default 90)
pathFile or directory to upload (supports globs)
Cross-jobUpload in one job, download in another with needs:
compression-level0 (none) to 9 (max), default 6
Common Patterns
Conditional Deployment
- name: Deploy to production if: github.ref == 'refs/heads/main' run: ./deploy.sh - name: Post PR comment if: github.event_name == 'pull_request' run: gh pr comment $PR --body "Build passed"
Useful Expressions
success()True if all previous steps passed
failure()True if any previous step failed
always()Run regardless of status (cleanup)
cancelled()True if workflow was cancelled
contains(github.ref, 'release')String contains check
startsWith(github.ref, 'refs/tags')String prefix check
hashFiles('**/lock*')SHA-256 of files (for cache keys)