GitHub Actions
Overview
GitHub Actions is a CI/CD platform that automates build, test, and deployment pipelines directly from GitHub repositories. Workflows are YAML files in .github/workflows/ triggered by events like pushes, pull requests, schedules, or manual dispatch. Each workflow contains one or more jobs that run on GitHub-hosted or self-hosted runners.
When to use: Automated testing, continuous deployment, release automation, scheduled tasks, multi-platform builds, dependency updates, container publishing, code quality checks, security scanning.
When NOT to use: Long-running services (use a proper hosting platform), heavy compute tasks exceeding runner limits (6-hour job timeout), tasks requiring persistent state between runs (use external storage), real-time event processing (use webhooks with a server).
Quick Reference
| Pattern | Syntax / Action | Key Points |
|---|---|---|
| Push trigger | on: push: branches: [main] | Filter by branch, path, or tag |
| PR trigger | on: pull_request: types: [opened, synchronize] | Defaults to opened, synchronize, reopened |
| Scheduled trigger | on: schedule: - cron: '0 6 * * 1' | UTC only, minimum 5-minute interval |
| Manual trigger | on: workflow_dispatch: inputs: | Define typed inputs for manual runs |
| Job dependencies | needs: [build, test] | Run jobs in sequence or parallel |
| Conditional job | if: github.ref == 'refs/heads/main' | Expression-based job/step filtering |
| Matrix strategy | strategy: matrix: node: [18, 20, 22] | Generates jobs for each combination |
| Dependency cache | actions/cache@v5 | Hash-based keys with restore-keys fallback |
| Setup with cache | actions/setup-node@v6 with cache: 'pnpm' | Built-in caching for package managers |
| Upload artifact | actions/upload-artifact@v4 | Share data between jobs or preserve outputs |
| Download artifact | actions/download-artifact@v4 | Retrieve artifacts from earlier jobs |
| Reusable workflow | uses: ./.github/workflows/reusable.yml | Called with workflow_call trigger |
| Composite action | action.yml with using: composite | Bundle multiple steps into one action |
| Concurrency | concurrency: group: ${{ github.ref }} | Cancel or queue duplicate runs |
| Environment secrets | ${{ secrets.API_KEY }} | Scoped to repo, org, or environment |
| OIDC authentication | permissions: id-token: write | Short-lived tokens for cloud providers |
| Step outputs | echo "key=value" >> "$GITHUB_OUTPUT" | Pass data between steps and jobs |
| Service containers | services: postgres: image: postgres:16 | Sidecar containers for integration tests |
| Timeout | timeout-minutes: 30 | Fail fast on hung jobs or steps |
| Attestations | actions/attest-build-provenance@v3 | SLSA build provenance for supply chain |
Expressions and Contexts
| Context | Example | Description |
|---|---|---|
github | github.ref_name, github.sha | Event metadata, repo info, actor |
env | env.NODE_ENV | Environment variables at current scope |
secrets | secrets.API_KEY | Encrypted secrets (masked in logs) |
inputs | inputs.environment | Workflow dispatch or reusable inputs |
matrix | matrix.node | Current matrix combination values |
steps | steps.build.outputs.version | Outputs from previous steps |
needs | needs.prepare.outputs.tag | Outputs from dependent jobs |
runner | runner.os, runner.arch | Runner environment info |
vars | vars.DEPLOY_URL | Repository or org configuration variables |
Common Mistakes
| Mistake | Correct Pattern |
|---|---|
| Using outdated action major versions | Pin to current major version (@v6) or commit SHA |
Missing persist-credentials: false | Set on checkout when using custom tokens or OIDC |
Broad permissions at workflow level | Set permissions: {} at workflow level, grant per-job |
| Cache key without dependency file hash | Include hashFiles('**/pnpm-lock.yaml') in cache key |
Secrets in if: conditions | Secrets cannot be used in if: expressions directly |
Using pull_request_target carelessly | Never run PR code with write permissions from pull_request_target |
| Not cancelling stale runs | Use concurrency with cancel-in-progress: true |
| Storing structured data as a single secret | Create individual secrets per value for proper log redaction |
| Referencing action tags without SHA pinning | Pin third-party actions to full commit SHA for supply chain safety |
| Hardcoding runner OS in scripts | Use runner.os context for cross-platform compatibility |
Using actions/cache without restore-keys | Always provide restore-keys for partial cache matches |
Interpolating user input in run: blocks | Pass untrusted values through env: to prevent script injection |
No timeout-minutes on jobs | Set explicit timeouts to fail fast on hung processes |
Using always() without scoping | Combine with status checks: if: always() && steps.x.outcome == 'success' |
Delegation
- Workflow debugging: Use
Exploreagent to inspect workflow run logs - Security auditing: Use
Taskagent to review permissions and secret usage - Code review: Delegate to
code-revieweragent for workflow PR reviews