Migrate from Vercel to Coolify
TL;DR
You can replace Vercel with Coolify on a $6-15/month Hetzner VPS and get 95% of the same developer experience — git push deploy, auto SSL, preview deployments, env vars — while cutting costs by 80-95%. The migration takes 3-4 hours. You give up: Vercel's global CDN edge network, Vercel Analytics, and zero-maintenance infrastructure. If you're spending more than ~$40/month on Vercel, the math strongly favors self-hosting.
Key Takeaways
- Coolify is the self-hosted Vercel — git push deploy, SSL, domains, preview deployments, one-click databases, all from a web UI
- Cost savings are dramatic — one reported migration went from $850/month on Vercel to $14/month on Coolify + Hetzner
- Next.js requires
output: 'standalone'innext.config.mjsto build a self-contained Docker image - Nixpacks handles most cases automatically — Coolify detects Next.js and builds without a Dockerfile; use Dockerfile for full control
- ISR and image optimization work, but require more care when scaling horizontally (single instance = no problem)
- What you give up: Vercel's Edge Network CDN, Vercel Analytics, automatic scaling from 0 to millions, and zero ops overhead
Why Developers Are Leaving Vercel
Vercel is genuinely excellent. The deployment experience is unmatched, and for small projects or teams with engineering bandwidth to burn, it's worth the premium. But the pricing model creates problems at scale:
- $0.15/GB bandwidth overage beyond the 1 TB Pro plan inclusion
- $0.60 per million function invocations plus CPU and memory charges
- $20/seat/month for the Pro plan, per team member
- A viral Reddit post or Product Hunt launch can generate a $500+ bill overnight
Real-world reports document a client paying $850/month on Vercel (bandwidth + Pro seats + edge functions) who migrated to Coolify + Hetzner for $14/month. Another documented case describes escaping a $95,000 Vercel bill. These are outliers, but the underlying math is structural: Vercel's pricing is designed for enterprise, not indie developers or growing startups.
"Moving from Vercel to Hetzner with Coolify was one of the best technical decisions I've made — not only did it give me more control, but it deepened my understanding of how modern deployment pipelines work." — Developer, Hetzner migration post
What Coolify Gives You
Coolify is an open-source, self-hostable PaaS with 32,000+ GitHub stars. It runs on your own server and provides:
| Feature | Vercel | Coolify |
|---|---|---|
| Git push → deploy | ✅ | ✅ |
| Auto SSL (Let's Encrypt) | ✅ | ✅ |
| Preview deployments (PRs) | ✅ | ✅ |
| Custom domains | ✅ | ✅ |
| Environment variables | ✅ | ✅ |
| One-click databases | ✅ (add-on $$) | ✅ (free) |
| Build logs | ✅ | ✅ |
| Rollbacks | ✅ | ✅ |
| Edge CDN | ✅ ✅ (global) | ❌ (single region) |
| Serverless scaling | ✅ (auto) | ❌ (manual) |
| Analytics | ✅ ($9+/mo) | ❌ (use PostHog/Plausible) |
| Vendor lock-in | High | None |
| Monthly cost (1 app) | $20-200+ | $6-15 |
Part 1: Server Setup
Choose a VPS
Coolify's minimum requirements: 2 vCPUs, 2 GB RAM, 20 GB storage. Recommended providers:
| Provider | Instance | Monthly | Notes |
|---|---|---|---|
| Hetzner | CX22 | ~€4.35 | Best value, EU data centers |
| Hetzner | CX32 | ~€8.49 | Comfortable for 2-3 Next.js apps |
| DigitalOcean | Basic 2GB | $12 | Good US/EU coverage |
| Vultr | Regular 2GB | $12 | Wide global regions |
Recommended: Hetzner CX32 (4 vCPU, 4GB RAM) at €8.49/month — comfortable headroom for a production Next.js app plus a database.
Install Coolify
SSH into your server as root (required) and run the one-line installer:
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
This installs Docker, sets up Coolify's container stack, and starts the web UI at port 8000. The install takes about 2 minutes.
Tip: On Ubuntu 24.04 LTS (recommended), the installer works without any extra configuration. On non-LTS Ubuntu versions, use the manual installation method from Coolify's docs.
After installation, access the Coolify dashboard at http://YOUR_SERVER_IP:8000 and create your admin account.
Point a Domain at Your Server
Add an A record pointing to your server's IP:
*.yourdomain.com → YOUR_SERVER_IP
yourdomain.com → YOUR_SERVER_IP
The wildcard * record lets Coolify auto-provision subdomains for preview deployments (e.g., pr-42.app.yourdomain.com).
Part 2: Prepare Your Next.js App
Enable Standalone Output
The most important change: add output: 'standalone' to your next.config.mjs. This creates a self-contained .next/standalone folder with everything needed to run the app — no node_modules required at runtime.
// next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
// Your existing config...
};
export default nextConfig;
This reduces Docker image sizes from 7+ GB to under 400 MB in most cases.
Add a Dockerfile (Optional but Recommended)
Coolify uses Nixpacks by default — it auto-detects Next.js and builds without a Dockerfile. For most apps this works fine. For production control, use this multi-stage Dockerfile:
# Dockerfile
FROM node:20-alpine AS base
# Stage 1: Dependencies
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \
fi
# Stage 2: Builder
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Build with standalone output
ENV NEXT_TELEMETRY_DISABLED 1
RUN \
if [ -f yarn.lock ]; then yarn run build; \
elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \
else echo "Lockfile not found." && exit 1; \
fi
# Stage 3: Production runner
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy public assets
COPY --from=builder /app/public ./public
# Copy standalone output
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"]
This is adapted from the official Next.js Docker example. Commit this to your repo root.
Create a .dockerignore
Dockerfile
.dockerignore
node_modules
npm-debug.log
.next
.git
.gitignore
README.md
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
Part 3: Deploy to Coolify
Connect Your GitHub Repository
- In Coolify dashboard → Sources → Add → GitHub App
- Install the Coolify GitHub App on your account/org
- Select your Next.js repository
Create a New Application
- Go to your Project → New Resource → Application
- Select GitHub as the source, choose your repo and branch (
main) - Set Build Pack:
- If you added a Dockerfile: choose Dockerfile
- Otherwise: choose Nixpacks (auto-detection)
- Set Port:
3000 - Set your Domain:
https://app.yourdomain.com
Coolify automatically provisions an SSL certificate from Let's Encrypt when you use https:// in the domain field.
Add Environment Variables
Go to your application → Environment Variables. Add your secrets one by one, marking sensitive values as Secret (encrypted at rest):
NEXT_PUBLIC_APP_URL=https://app.yourdomain.com
DATABASE_URL=postgresql://user:pass@host:5432/db
NEXTAUTH_URL=https://app.yourdomain.com
NEXTAUTH_SECRET=your-secret-here
STRIPE_SECRET_KEY=sk_live_...
RESEND_API_KEY=re_...
Important:
NEXTAUTH_URLmust be updated from your Vercel URL to your new domain. Same for any webhooks registered in Stripe, GitHub, etc.
First Deploy
Click Deploy. Coolify will:
- Clone your repo
- Run the Docker build (or Nixpacks build)
- Start the container
- Route traffic through Traefik (the built-in reverse proxy)
- Issue the Let's Encrypt certificate
Watch the Deployment Logs for the build output. A cold build takes 2-5 minutes.
Part 4: Set Up Auto-Deploy (Git Push → Deploy)
Automatic Webhook Deployment
Coolify creates a webhook in your GitHub repo automatically when you connect via the GitHub App. Every push to your configured branch triggers a rebuild and redeploy with zero downtime.
Preview Deployments for Pull Requests
To enable Vercel-style PR preview URLs:
- Application → Advanced → Preview Deployments → Enable
- Configure the preview URL pattern:
pr-{{pr_id}}.app.yourdomain.com - Add preview-specific environment variables (separate from production)
When you open a PR, Coolify deploys a preview URL and posts a comment with the link — identical to Vercel's behavior.
GitHub Actions Integration (Advanced)
If you want tests to pass before deploying, use the Coolify API:
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- name: Trigger Coolify deployment
run: |
curl -X GET "${{ secrets.COOLIFY_WEBHOOK_URL }}" \
-H "Authorization: Bearer ${{ secrets.COOLIFY_API_TOKEN }}"
Set COOLIFY_WEBHOOK_URL and COOLIFY_API_TOKEN as GitHub repository secrets (get these from Coolify: Settings → API → Create Token).
Part 5: Database Migration
Vercel's Postgres add-on costs $20+/month. In Coolify, add a Postgres database for free (using your server's storage):
- Project → New Resource → Database → PostgreSQL
- Set version, credentials, and database name
- Copy the internal connection string:
postgresql://user:pass@db:5432/mydb
Internal networking: Services in the same Coolify project can communicate via container name (e.g.,
db:5432). Use the internal URL for your app'sDATABASE_URLto avoid unnecessary network hops.
Run your migrations against the new database before switching DNS:
# Connect from your local machine via SSH tunnel
ssh -L 5432:localhost:5432 root@YOUR_SERVER_IP
# Run migrations
DATABASE_URL="postgresql://user:pass@localhost:5432/mydb" npx prisma migrate deploy
# or
DATABASE_URL="postgresql://user:pass@localhost:5432/mydb" npx drizzle-kit migrate
Part 6: DNS Cutover
Zero-downtime migration steps:
- Keep Vercel running until you've verified Coolify works
- Deploy to Coolify, test thoroughly at
https://staging.yourdomain.com - Verify all env vars, webhooks, and integrations work
- Lower your DNS TTL to 60 seconds (24 hours before switching)
- Update DNS: point
yourdomain.comA record to your VPS IP - Wait for propagation (~5 minutes with low TTL)
- Verify production works on Coolify
- Deactivate the Vercel project (keep 30 days before deleting)
What You Give Up
Be honest about the trade-offs before migrating:
1. Global CDN Edge Network
Vercel distributes your app across 40+ edge regions globally. On a single Hetzner VPS in Nuremberg, users in Singapore see higher latency. Mitigation: Add Cloudflare's free CDN in front (proxy your domain through Cloudflare → static assets are cached globally).
2. Automatic Scaling
Vercel scales to zero and back up automatically. Coolify runs a fixed container — if you get 100K concurrent users, your VPS might struggle. Mitigation: Upgrade the VPS, or use Docker Swarm / multi-server Coolify for horizontal scaling.
3. ISR Caching at Scale
Next.js ISR uses the local filesystem by default. On a single instance this works fine. On multiple instances, caches go out of sync. Mitigation: Single instance = no problem. For multi-instance setups, configure a Redis cache handler.
4. Zero Ops
Vercel handles security patches, runtime updates, and infrastructure. Self-hosting means you own the server. Mitigation: Coolify has an auto-update feature; enable it for non-breaking updates. Budget 1-2 hours/month for maintenance.
5. Vercel Analytics
Not available self-hosted. Alternatives: Plausible Analytics (open source, $9/mo managed or free self-hosted), PostHog (open source, generous free tier).
Cost Comparison
| Scenario | Vercel | Coolify + Hetzner |
|---|---|---|
| 1 small app | $20/mo (Pro) | $6/mo (CX22) |
| 1 app + Postgres | $40/mo | $6/mo |
| 3 apps + 2 databases | $60-150/mo | $9/mo (CX32) |
| High traffic (100GB bandwidth) | $35/mo | $9/mo |
| Team of 3 | $60/mo (3 seats) | $9/mo |
Break-even: If you're paying more than ~$30/month on Vercel, self-hosting pays for itself including the 3-4 hours of setup time.
Methodology
- Coolify documentation reviewed: coolify.io/docs
- Next.js self-hosting guide: nextjs.org/docs/app/guides/self-hosting
- Community migration reports from Dev.to, Medium, Hacker News (2025-2026)
- Vercel pricing model from vercel.com/pricing
- Hetzner pricing from hetzner.com/cloud
Ready to explore Coolify vs other self-hosted PaaS options? See OSSAlt's Coolify alternatives comparison.