DevOps
GitHub
CI/CD
Tutorial
Best Practices
Ask anything about this article
Hi! I've read this article.
What would you like to know?
@farhan
Manual deployments are error-prone, slow, and don't scale. CI/CD (Continuous Integration / Continuous Deployment) automates the entire process from code commit to production deployment. GitHub Actions makes this incredibly easy.
Push Code → Run Tests → Build → Deploy to Staging → Deploy to Production
(CI) (CI) (CD) (CD)
Create .github/workflows/ci.yml:
yamlname: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test
- name: Build
run: npm run build
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Deploy to Vercel
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'
yamlon:
push: # On every push
pull_request: # On PR creation/update
schedule:
- cron: '0 0 * * 1' # Every Monday at midnight
workflow_dispatch: # Manual trigger from UI
yaml- name: Cache node modules
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
yamljobs:
test:
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
yamlenv:
NODE_ENV: production
steps:
- name: Deploy
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
API_KEY: ${{ secrets.API_KEY }}
run: npm run deploy
yamlname: Production Pipeline
on:
push:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run lint
test:
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- run: npm ci && npm test
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
deploy-staging:
needs: build
runs-on: ubuntu-latest
environment: staging
steps:
- run: echo "Deploy to staging..."
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production
steps:
- run: echo "Deploy to production..."
Automate everything. Your future self will thank you.