Docs / Cloud & DevOps / CI/CD Pipeline with GitHub Actions

CI/CD Pipeline with GitHub Actions

By Admin · Jan 15, 2026 · Updated Apr 23, 2026 · 691 views · 2 min read

What is CI/CD?

  • CI (Continuous Integration) — automatically test code on every push
  • CD (Continuous Deployment) — automatically deploy to production after tests pass

Basic Workflow

# .github/workflows/deploy.yml
name: Test and Deploy

on:
  push:
    branches: [main]
  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 tests
        run: npm test

      - name: Run linter
        run: npm run lint

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to server
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: deploy
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /var/www/myapp
            git pull origin main
            npm ci --production
            npm run build
            pm2 restart myapp

Setting Up Secrets

In your GitHub repository:

  1. Go to Settings → Secrets and variables → Actions
  2. Add secrets:
Secret Value
SERVER_HOST Your server IP
SSH_PRIVATE_KEY Deploy key private key
DATABASE_URL Production database URL

Docker Build and Push

  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: myorg/myapp:${{ github.sha }},myorg/myapp:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

Matrix Testing

Test across multiple versions:

  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]
        os: [ubuntu-latest, macos-latest]
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

Caching Dependencies

      - uses: actions/cache@v4
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-

Tip Keep your CI pipeline under 5 minutes. Slow pipelines discourage frequent commits and slow down the entire team.

Was this article helpful?