Docs / Migration Guides / Migrate from Vercel to Self-Hosted

Migrate from Vercel to Self-Hosted

By Admin · Mar 15, 2026 · Updated Apr 24, 2026 · 364 views · 2 min read

Why Self-Host Instead of Vercel?

Vercel excels at serverless deployment but can become expensive at scale, especially with function invocations, bandwidth overages, and team seats. Self-hosting gives you predictable costs, no vendor lock-in, and full control over your infrastructure.

Migration Options

  • Static export: For static/SSG sites, export HTML and serve with Nginx
  • Node.js server: For SSR/ISR Next.js apps, run the Node.js server directly
  • Docker: Containerize for portability and easy deployment
  • Coolify/CapRover: Self-hosted PaaS for Vercel-like experience

Static Site Export

# In next.config.js:
module.exports = {
  output: "export",
}

# Build static export
npm run build

# The out/ directory contains your static site
# Serve with Nginx:
server {
    listen 80;
    server_name example.com;
    root /var/www/example.com;
    index index.html;

    location / {
        try_files $uri $uri.html $uri/ /404.html;
    }
}

SSR Next.js with Node.js

# Build the application
npm run build

# Start in production
NODE_ENV=production npm start
# Or: node .next/standalone/server.js

# Use PM2 for process management
npm install -g pm2
pm2 start npm --name "my-app" -- start
pm2 save
pm2 startup

Docker Deployment

# Dockerfile for Next.js
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]

# docker-compose.yml
version: "3.8"
services:
  app:
    build: .
    ports: ["3000:3000"]
    environment:
      - NODE_ENV=production
    restart: always

Nginx Reverse Proxy

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /_next/static/ {
        alias /var/www/app/.next/static/;
        expires 365d;
        access_log off;
    }
}

Replacing Vercel Features

  • Edge Functions: Use Nginx + Lua or Cloudflare Workers
  • Analytics: Plausible or Umami (self-hosted)
  • Preview Deployments: Coolify supports PR previews
  • Serverless Functions: Convert to API routes in your Node.js server
  • Image Optimization: Use next/image with sharp (works self-hosted)

CI/CD Setup

# GitHub Actions for automated deployment
name: Deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: ssh user@server "cd /app && git pull && npm ci && npm run build && pm2 restart my-app"

Was this article helpful?