GitHub Actions: Your Free CI/CD Pipeline
GitHub Actions runs workflows in response to events (push, pull request, schedule). It's free for public repos and comes with 2000 minutes/month for private repos. No separate CI service needed.
Basic Workflow
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
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 testKey Concepts
| Concept | Meaning |
|---|---|
| Workflow | A YAML file in .github/workflows/ |
| Event | What triggers the workflow (push, PR, schedule, manual) |
| Job | A set of steps that run on a runner (can run in parallel) |
| Step | Individual command or action |
| Action | Reusable unit (e.g., actions/checkout@v4) |
| Runner | The VM that executes the job |
| Secret | Encrypted variable (Settings → Secrets) |
Full CI/CD: Test → Build → Deploy
name: CI/CD
on:
push:
branches: [main]
jobs:
test:
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 test
- run: npm run build
deploy:
needs: test # only runs if test passes
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run build
- name: Deploy to production
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
run: |
npx wrangler deploy --token $DEPLOY_TOKENMatrix Builds (Test Multiple Versions)
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm testUseful Patterns
# Cache dependencies
- uses: actions/setup-node@v4
with:
cache: 'npm' # auto-caches node_modules
# Run only when specific files change
on:
push:
paths:
- 'src/**'
- 'package.json'
# Scheduled (cron)
on:
schedule:
- cron: '0 8 * * 1' # Every Monday at 8 AM UTC
# Manual trigger
on:
workflow_dispatch:
inputs:
environment:
description: 'Deploy environment'
required: true
default: 'staging'Tips
- Use
actions/checkout@v4(always pin major version) - Enable dependency caching for faster runs
- Use
needs:to create job dependencies - Keep secrets in Settings → Secrets, reference with
${{ secrets.NAME }} - Use
if:conditions to control when jobs/steps run
Validate your YAML: YAML Formatter — check your workflow file syntax.