Skip to main content
Back to Blog
Tutorials
3 min read
November 11, 2024

How to Set Up CI/CD with GitHub Actions for Next.js

Automate testing, linting, and deployment for your Next.js app with GitHub Actions. Build pipelines that catch errors before production.

Ryel Banfield

Founder & Lead Developer

Continuous integration and continuous deployment ensure every code change is automatically tested and deployed. Here is how to set it up with GitHub Actions.

Step 1: Basic CI Pipeline

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm lint

  typecheck:
    name: Type Check
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm tsc --noEmit

  test:
    name: Test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm test

  build:
    name: Build
    runs-on: ubuntu-latest
    needs: [lint, typecheck, test]
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm build

Step 2: Cache Dependencies

Speed up builds by caching pnpm store:

- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
  with:
    node-version: 20
    cache: pnpm

This automatically caches and restores pnpm dependencies.

Step 3: Cache Next.js Build

- uses: actions/cache@v4
  with:
    path: ${{ github.workspace }}/.next/cache
    key: nextjs-${{ hashFiles('pnpm-lock.yaml') }}-${{ hashFiles('**/*.ts', '**/*.tsx') }}
    restore-keys: |
      nextjs-${{ hashFiles('pnpm-lock.yaml') }}-

Step 4: Add E2E Tests

e2e:
  name: E2E Tests
  runs-on: ubuntu-latest
  needs: [build]
  steps:
    - uses: actions/checkout@v4
    - uses: pnpm/action-setup@v4
    - uses: actions/setup-node@v4
      with:
        node-version: 20
        cache: pnpm
    - run: pnpm install --frozen-lockfile
    - run: npx playwright install --with-deps chromium
    - run: pnpm build
    - run: pnpm test:e2e --project=chromium
    - uses: actions/upload-artifact@v4
      if: failure()
      with:
        name: playwright-report
        path: playwright-report/
        retention-days: 7

Step 5: Environment Variables

env:
  DATABASE_URL: ${{ secrets.DATABASE_URL }}
  NEXT_PUBLIC_SITE_URL: ${{ vars.NEXT_PUBLIC_SITE_URL }}

Set secrets in GitHub repository settings under Settings → Secrets and variables → Actions.

Step 6: Deploy to Vercel

Vercel deploys automatically on push. For custom control:

deploy:
  name: Deploy
  runs-on: ubuntu-latest
  needs: [build, e2e]
  if: github.ref == 'refs/heads/main'
  steps:
    - uses: actions/checkout@v4
    - 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"

Step 7: Preview Deployments for PRs

preview:
  name: Preview Deploy
  runs-on: ubuntu-latest
  if: github.event_name == 'pull_request'
  needs: [lint, typecheck, test]
  steps:
    - uses: actions/checkout@v4
    - uses: amondnet/vercel-action@v25
      id: deploy
      with:
        vercel-token: ${{ secrets.VERCEL_TOKEN }}
        vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
        vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
    - uses: actions/github-script@v7
      with:
        script: |
          github.rest.issues.createComment({
            issue_number: context.issue.number,
            owner: context.repo.owner,
            repo: context.repo.repo,
            body: `Preview: ${{ steps.deploy.outputs.preview-url }}`
          })

Step 8: Database Migrations

migrate:
  name: Run Migrations
  runs-on: ubuntu-latest
  needs: [build]
  if: github.ref == 'refs/heads/main'
  steps:
    - uses: actions/checkout@v4
    - uses: pnpm/action-setup@v4
    - uses: actions/setup-node@v4
      with:
        node-version: 20
        cache: pnpm
    - run: pnpm install --frozen-lockfile
    - run: pnpm db:migrate
      env:
        DATABASE_URL: ${{ secrets.DATABASE_URL }}

Step 9: Scheduled Health Checks

# .github/workflows/health.yml
name: Health Check

on:
  schedule:
    - cron: "0 */6 * * *" # Every 6 hours

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - name: Check site status
        run: |
          STATUS=$(curl -o /dev/null -s -w "%{http_code}" https://yoursite.com)
          if [ "$STATUS" != "200" ]; then
            echo "Site returned $STATUS"
            exit 1
          fi

Step 10: Full Pipeline Summary

PR opened → lint + typecheck + test (parallel)
         → build
         → e2e tests
         → preview deploy + comment

Merge to main → lint + typecheck + test (parallel)
              → build
              → e2e tests
              → run migrations
              → deploy to production

Add Scripts to package.json

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "test": "vitest run",
    "test:e2e": "playwright test",
    "db:migrate": "drizzle-kit migrate"
  }
}

Need DevOps for Your Project?

We set up CI/CD pipelines, automated testing, and deployment workflows for web applications. Contact us to streamline your development process.

CI/CDGitHub ActionsNext.jsdeploymenttutorial

Ready to Start Your Project?

RCB Software builds world-class websites and applications for businesses worldwide.

Get in Touch

Related Articles