DEV Community

Atlas Whoff
Atlas Whoff

Posted on

GitHub Actions CI/CD for Next.js: Test, Build, Deploy on Every Push

GitHub Actions CI/CD for Next.js: Test, Build, Deploy on Every Push

A solid CI/CD pipeline catches bugs before they reach production and automates deploys.
Here's a production-ready setup for Next.js.

Basic Pipeline Structure

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

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

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run lint
      - run: npm run type-check
      - run: npm test

  deploy:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: vercel/action@v3
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'
Enter fullscreen mode Exit fullscreen mode

Database Migrations in CI

  migrate:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - name: Run migrations
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
        run: npx prisma migrate deploy

  deploy:
    needs: [test, migrate]
    # ... rest of deploy job
Enter fullscreen mode Exit fullscreen mode

Caching Dependencies

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'  # caches ~/.npm

      # Also cache Next.js build cache
      - uses: actions/cache@v4
        with:
          path: |
            ~/.npm
            ${{ github.workspace }}/.next/cache
          key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
          restore-keys: |
            ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
Enter fullscreen mode Exit fullscreen mode

This reduces build times by 40-60% on repeated runs.

Preview Deployments for PRs

  preview:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: vercel/action@v3
        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 }}`
            })
Enter fullscreen mode Exit fullscreen mode

Running Tests with a Database

  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: testpassword
          POSTGRES_DB: testdb
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - name: Setup test database
        env:
          DATABASE_URL: postgresql://postgres:testpassword@localhost:5432/testdb
        run: npx prisma migrate deploy
      - name: Run tests
        env:
          DATABASE_URL: postgresql://postgres:testpassword@localhost:5432/testdb
        run: npm test
Enter fullscreen mode Exit fullscreen mode

Environment Secrets Management

      - name: Build
        env:
          NEXT_PUBLIC_API_URL: ${{ vars.API_URL }}         # non-sensitive
          DATABASE_URL: ${{ secrets.DATABASE_URL }}        # sensitive
          STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET }}  # sensitive
        run: npm run build
Enter fullscreen mode Exit fullscreen mode

Use vars (variables) for non-sensitive config, secrets for credentials.

Notifications on Failure

      - name: Notify on failure
        if: failure()
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {"text": "Deploy failed on ${{ github.ref }} by ${{ github.actor }}"}
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
Enter fullscreen mode Exit fullscreen mode

The Ship Fast Skill Pack includes a /deploy skill that generates complete GitHub Actions workflows for your stack — CI, preview deploys, and production. $49 one-time.

Top comments (0)