Manual deployments are the enemy of scaling. Running npm run build locally, dragging files to a server via FTP, or manually merging branches leads to human error, downtime, and broken code in production. Continuous Integration and Continuous Deployment (CI/CD) is the practice of automating the entire lifecycle: every code push triggers an isolated virtual machine that lints the code, runs the test suite, builds the production bundle, and deploys it to a global CDN. This guarantees that your main branch is always stable and releasable.


Module 1: GitHub Actions Architecture

GitHub Actions is deeply integrated into GitHub repositories. A Workflow is defined in a YAML file inside the .github/workflows/ directory.

Core Concepts

  • Workflow: The entire automated process (e.g., 'CI Pipeline').
  • Event (on): What triggers the workflow. Common triggers: push, pull_request, or a cron schedule.
  • Job: A set of steps. Jobs run in parallel by default on separate virtual machines (runners).
  • Step: A sequential command (run: npm test) or a pre-built community action (uses: actions/checkout).

Module 2: Building the Continuous Integration (CI) Pipeline

The CI pipeline acts as a gatekeeper. We configure repository settings to block Pull Requests from merging until this pipeline passes successfully.

.github/workflows/ci.ymlyaml
name: Frontend Quality Gate

on:
  pull_request:
    branches: [ main, develop ]

jobs:
  # Job 1: Static Analysis & Unit Tests
  validate:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v3

      - name: Setup Node.js Environment
        uses: actions/setup-node@v3
        with:
          node-version: '18.x'
          cache: 'npm' # Automatically caches ~/.npm to speed up future runs by minutes

      # Always use 'npm ci' in pipelines. It strictly adheres to package-lock.json
      # and deletes node_modules before installing, ensuring a clean slate.
      - name: Install Dependencies
        run: npm ci

      - name: Run ESLint & Prettier
        run: npm run lint

      - name: Run Unit Tests (Jest/Vitest)
        run: npm run test:unit

      # Ensure the project actually compiles
      - name: Verify Production Build
        run: npm run build

Module 3: End-to-End (E2E) Testing in Pipelines

Unit tests ensure functions work. E2E tests (like Playwright or Cypress) spin up a real Chromium browser, navigate to your app, and simulate a user clicking buttons. Because they are slow, we run them in parallel with the validation job, or only after the validation job succeeds.

Adding Playwright Jobyaml
  e2e-tests:
    needs: validate # Wait for the 'validate' job to pass first
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm ci
      
      # Playwright requires the actual browser binaries to be installed on the Linux runner
      - name: Install Playwright Browsers
        run: npx playwright install --with-deps
        
      - name: Run Playwright Test Suite
        run: npx playwright test

      # Upload trace logs if a test fails so developers can debug the failure visually
      - uses: actions/upload-artifact@v3
        if: always()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 7

Module 4: Continuous Deployment (CD)

Once the PR is merged into main, the CD pipeline takes over to deploy the app to production. Here is an example of deploying a Next.js app to Vercel.

.github/workflows/cd.ymlyaml
name: Deploy to Production

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v20
        with:
          # These secrets are securely stored in GitHub Repository Secrets
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod' # Forces a production deployment