GitHub Actions & CI/CD
Quick Summary
GitHub Actions is GitHub's built-in automation platform. It lets you run code (tests, builds, deployments) automatically when events happen in your repository — like pushing code, opening a PR, or creating a release. This is the backbone of modern CI/CD (Continuous Integration / Continuous Deployment).
Core Concepts
flowchart LR
E["Event<br/>(push, PR, schedule)"] --> W["Workflow<br/>(.yml file)"]
W --> J1["Job 1<br/>(build)"]
W --> J2["Job 2<br/>(test)"]
J1 --> S1["Step 1: Checkout"]
J1 --> S2["Step 2: Install deps"]
J1 --> S3["Step 3: Build"]
J2 --> S4["Step 1: Checkout"]
J2 --> S5["Step 2: Run tests"]
| Concept | Definition |
|---|---|
| Workflow | An automated process defined in a .yml file |
| Event | What triggers the workflow (push, PR, cron, manual) |
| Job | A set of steps that run on the same machine |
| Step | A single command or action within a job |
| Action | A reusable unit of code (from GitHub Marketplace or custom) |
| Runner | The machine that executes the job (GitHub-hosted or self-hosted) |
Your First Workflow
Create .github/workflows/ci.yml:
name: CI Pipeline
# When to run
on:
push:
branches: [main]
pull_request:
branches: [main]
# What to do
jobs:
test:
runs-on: ubuntu-latest
steps:
# Checkout the code
- uses: actions/checkout@v4
# Set up Node.js
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
# Install dependencies
- run: npm ci
# Run tests
- run: npm test
# Run linter
- run: npm run lint
Common Triggers
on:
# Push to specific branches
push:
branches: [main, develop]
paths:
- 'src/**' # Only when src/ changes
# Pull request events
pull_request:
types: [opened, synchronize]
# Scheduled (cron)
schedule:
- cron: '0 2 * * 1' # Every Monday at 2 AM UTC
# Manual trigger
workflow_dispatch:
inputs:
environment:
description: 'Deploy target'
required: true
default: 'staging'
# On release
release:
types: [published]
Real-World Examples
Node.js CI/CD Pipeline
name: Node.js CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
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 test
deploy:
needs: test # Only run after tests pass
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- name: Deploy to production
run: rsync -avz ./dist/ user@server:/var/www/app/
env:
SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
Docker Build & Push
name: Docker Build
on:
push:
tags: ['v*']
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- uses: docker/build-push-action@v5
with:
push: true
tags: myapp:${{ github.ref_name }}
Secrets and Environment Variables
# Store secrets in: Repository Settings → Secrets → Actions
steps:
- name: Deploy
run: |
echo "$SSH_KEY" > key.pem
chmod 600 key.pem
ssh -i key.pem user@${{ secrets.SERVER_IP }} "deploy.sh"
env:
SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
Never hardcode secrets
Always use ${{ secrets.NAME }}. GitHub masks secret values in logs automatically.
Useful Actions (Marketplace)
| Action | Purpose |
|---|---|
actions/checkout@v4 | Clone the repository |
actions/setup-node@v4 | Install Node.js |
actions/setup-python@v5 | Install Python |
actions/cache@v4 | Cache dependencies |
docker/build-push-action@v5 | Build and push Docker images |
peaceiris/actions-gh-pages@v4 | Deploy to GitHub Pages |
Best Practices
- Run tests on every PR — catch bugs before merging
- Use a build matrix for multiple versions/platforms
- Cache dependencies (
actions/cache) — speeds up workflows significantly - Use branch protection rules — require CI to pass before merging
- Keep secrets in GitHub Secrets — never in code
- Use
needs:for dependencies between jobs
What's Next
- Pages & Releases — Host documentation and publish releases
- Security Features — Dependabot, code scanning, and secret scanning