| name | github-actions |
| description | Debug, optimize, and secure GitHub Actions workflows. Use this skill when writing CI/CD pipelines, fixing failing workflows, or improving build times. |
| alwaysApply | false |
GitHub Actions
You are a CI/CD expert specializing in GitHub Actions. Apply these patterns when writing, debugging, or optimizing workflows.
Workflow Structure Best Practices
Standard CI Workflow
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run lint
test:
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm test
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run build
Speed Optimization
1. Cache Dependencies
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- uses: actions/setup-go@v5
with:
go-version: '1.23'
cache: true
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: ${{ runner.os }}-pip-
2. Parallel Jobs
jobs:
lint:
runs-on: ubuntu-latest
test-unit:
runs-on: ubuntu-latest
test-integration:
runs-on: ubuntu-latest
deploy:
needs: [lint, test-unit, test-integration]
3. Skip Unnecessary Runs
on:
push:
paths-ignore:
- '**.md'
- 'docs/**'
- '.github/ISSUE_TEMPLATE/**'
branches: [main]
4. Use Concurrency
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
5. Matrix Builds (When Needed)
strategy:
matrix:
node: [20, 22]
os: [ubuntu-latest, macos-latest]
fail-fast: true
Debugging Failed Workflows
Common Failures and Fixes
| Error | Cause | Fix |
|---|
Permission denied | Missing permissions block | Add permissions: contents: read |
Node.js 16 deprecation | Old action version | Update to @v4 |
npm ci fails | package-lock.json out of sync | Run npm install locally, commit lock file |
GITHUB_TOKEN unauthorized | Insufficient permissions | Add permissions: block with needed scopes |
| Cache miss every time | Bad cache key | Use hashFiles() on lock files |
| Timeout | Long-running tests | Add timeout-minutes: 15 to job |
Debug Techniques
- run: env | sort
- run: echo '${{ toJSON(github) }}'
- uses: mxschmitt/action-tmate@v3
if: failure()
Security
Pin Action Versions by SHA
- uses: actions/checkout@v4
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
Limit Permissions
permissions:
contents: read
pull-requests: write
Protect Secrets
jobs:
deploy:
environment: production
steps:
- run: deploy.sh
env:
API_KEY: ${{ secrets.PROD_API_KEY }}
Don't Trust PR Input
- run: echo "PR: ${{ github.event.pull_request.title }}"
- run: echo "PR: $PR_TITLE"
env:
PR_TITLE: ${{ github.event.pull_request.title }}
Reusable Workflows
Create a Reusable Workflow
name: Reusable Test
on:
workflow_call:
inputs:
node-version:
type: string
default: '22'
secrets:
NPM_TOKEN:
required: false
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- run: npm ci
- run: npm test
Use a Reusable Workflow
jobs:
test:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '22'
secrets: inherit
Cost Optimization
- Use
ubuntu-latest (cheapest runner) unless macOS/Windows needed
- Set
timeout-minutes to prevent runaway jobs
- Use
concurrency to cancel stale runs
- Cache aggressively — every
npm ci without cache costs time
- Use
paths filters to skip irrelevant builds
- Consider self-hosted runners for heavy workloads