CI/CD Pipeline for Next.js: GitHub Actions to Vercel and Docker Deployments

A well-designed CI/CD pipeline catches bugs before they reach production, provides preview environments for every pull request, and deploys changes with zero downtime. For Next.js applications, the pipeline needs to handle static generation, server-side rendered pages, API routes, and Docker-based self-hosting. Here is how to build it.
Continuous Integration: Testing and Linting
Every push to any branch should run your test suite, type checking, and linting. Keep the CI pipeline fast by using caching and only running jobs relevant to the changed code.
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: TypeScript check
run: pnpm typecheck
- name: Lint
run: pnpm lint
- name: Unit tests
run: pnpm test -- --coverage
- name: Upload coverage
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
Add caching for Turborepo if you are in a monorepo. This reduces CI times from minutes to seconds for unchanged packages.
Preview Deployments for Every Pull Request
Vercel automatically creates preview deployments for every PR when your repo is connected. If you self-host or use Docker, create ephemeral preview environments using GitHub Actions.
deploy-preview:
if: github.event_name == 'pull_request'
needs: quality
runs-on: ubuntu-latest
environment:
name: preview
url: ${{ steps.deploy.outputs.url }}
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: |
docker build \
--build-arg NEXT_PUBLIC_API_URL=${{ secrets.STAGING_API_URL }} \
-t app:${{ github.sha }} .
- name: Deploy to preview cluster
run: |
kubectl set image deployment/app-preview \
app=app:${{ github.sha }} \
--namespace=preview
kubectl rollout status deployment/app-preview \
--namespace=preview --timeout=5m
- name: Comment PR with URL
uses: actions/github-script@v7
with:
script: |
const url = `https://pr-${{ github.event.number }}.preview.example.com`
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `Preview deployed: ${url}`,
})
Each preview gets its own URL. The PR author, reviewer, and QA team can test changes in isolation before merging.
Production Deployment Pipeline
Merging to the main branch triggers the production pipeline. This should include build, test, deploy, smoke test, and rollback capability.
# .github/workflows/deploy.yml
name: Deploy Production
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
outputs:
image: ${{ steps.build.outputs.image }}
steps:
- uses: actions/checkout@v4
- name: Build and push Docker image
id: build
run: |
docker build \
--cache-from ${{ secrets.REGISTRY }}/app:latest \
-t ${{ secrets.REGISTRY }}/app:${{ github.sha }} \
-t ${{ secrets.REGISTRY }}/app:latest .
docker push ${{ secrets.REGISTRY }}/app:${{ github.sha }}
docker push ${{ secrets.REGISTRY }}/app:latest
echo "image=${{ secrets.REGISTRY }}/app:${{ github.sha }}" >> $GITHUB_OUTPUT
deploy:
needs: build
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy to production cluster
run: |
kubectl set image deployment/app \
app=${{ needs.build.outputs.image }} \
--namespace=production --record
kubectl rollout status deployment/app \
--namespace=production --timeout=5m
smoke-test:
needs: deploy
runs-on: ubuntu-latest
steps:
- name: Run smoke tests
run: |
curl --fail --retry 10 --retry-delay 5 \
https://example.com/api/health
curl --fail --retry 5 --retry-delay 3 \
https://example.com | grep -q '<html'
rollback:
if: failure()
needs: [deploy, smoke-test]
runs-on: ubuntu-latest
steps:
- name: Rollback to previous version
run: |
kubectl rollout undo deployment/app \
--namespace=production
The rollback job only runs if either deployment or smoke tests fail. Automatic rollbacks prevent bad deployments from affecting users for more than a few minutes.
Dockerfile for Next.js Production
Your Docker image should be optimized for Next.js standalone output, which includes only the files needed to run the application.
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]
Set output: 'standalone' in next.config.ts to create a self-contained build directory. This dramatically reduces the Docker image size and startup time.
Monitoring the Pipeline
Add Slack or Discord notifications for pipeline status. Track deployment frequency, change failure rate, and mean time to recovery (MTTR). A healthy pipeline should deploy multiple times a day with a change failure rate under 5%.
Building and maintaining CI/CD pipelines requires deep knowledge of both your application architecture and your deployment infrastructure. At SoniNow, we design deployment pipelines that automate testing, preview deployments, and production rollouts with built-in safety mechanisms and monitoring.
Need a CI/CD pipeline for your Next.js app? Contact SoniNow to discuss your deployment workflow and infrastructure requirements.
Related Insights

CI/CD Pipeline Design: Automating Build, Test, and Deployment Workflows
A guide to designing CI/CD pipelines that automate build, test, and deployment including GitHub Actions, GitLab CI, environment strategies, and rollback patterns.

Database Migration Strategies: Zero-Downtime Schema Changes
Learn zero-downtime database migration strategies including expand-contract patterns, online schema changes, backward-compatible migrations, and rollback planning.

DevOps ROI: Building a Business Case for DevOps Transformation
Build a data-driven business case for DevOps transformation. Quantify savings in deployment frequency, lead time, and MTTR to secure executive buy-in.