Back to Article List

How to migrate from Vercel to Coolify

How to migrate from Vercel to Coolify

Vercel built the best Next.js deploy experience on the internet. The only catch is that the bill grows in ways that are hard to predict, particularly the bandwidth tier and the function-invocation pricing on apps that started small and got popular. A Next.js site doing 10 million pageviews a month can easily clear a thousand dollars on Vercel, the same site on a Coolify VPS comes out at roughly 30 dollars.

This guide walks through migrating a Next.js app from Vercel to a Coolify setup, preserving the things you actually liked about Vercel (push to deploy, preview deployments, automatic SSL, custom domains) and replacing the things that come with caveats once you self-host (image optimization, ISR caching, edge runtime). Written against Coolify v4.0.0 and Next.js 15 and 16.

If you've never touched Coolify before, the getting started guide covers initial dashboard access and securing the install. Once you have Coolify reachable, the rest of this is sequential.

What Vercel does that Coolify doesn't (and what you can do about it)

The first migration honesty check. Vercel is a managed edge platform, Coolify is a self-hosted PaaS that runs on one or more VPS instances. There are five Vercel features that don't have a one-to-one equivalent on Coolify and you should know how each one will land before you pull the trigger on the migration.

Image optimization at the edge

Vercel runs /_next/image on their edge, scales globally, caches responses by default. On Coolify, the same endpoint runs in your Node.js process on your VPS. For most sites this is fine, your VPS handles the load and sharp does the actual image processing fast enough. For image-heavy sites you'll want to either install sharp explicitly (it's listed as optional in some Next.js versions), use a CDN-backed image loader (Cloudflare Images, Imgix, Cloudinary) or set images.unoptimized: true and serve pre-optimized images directly. The Next.js on Coolify guide goes into the three options in detail.

ISR and on-demand revalidation

Incremental Static Regeneration mostly just works on a self-hosted Next.js. The framework writes regenerated pages to the filesystem and serves them. The catch is that on Vercel the cache is shared across all edge regions, on Coolify the cache lives on disk on your one VPS. If you scale to multiple Coolify servers you'll need to either point them at shared storage or use the cache-handler custom cache feature in Next.js 14+ to back the cache with Redis. For single-server setups, the default works.

Edge runtime middleware and functions

Anything you wrote with export const runtime = 'edge' won't work on Coolify the way Vercel runs it. Edge runtime is a stripped-down V8 environment that doesn't exist outside Vercel's infrastructure. The fix is to remove the edge runtime export so the function runs in standard Node.js. Most edge functions port directly. The few that don't are the ones using Vercel-specific APIs (geolocation headers, edge config, KV) which we'll cover in a moment.

Vercel KV, Postgres, Blob

If you've adopted Vercel's storage products, you're swapping them for Coolify-managed equivalents. Vercel KV becomes a Coolify Redis (one-click). Vercel Postgres becomes a Coolify PostgreSQL (one-click). Vercel Blob becomes either a self-hosted MinIO or any external S3-compatible storage. The connection details change but the API surface for your app code stays the same if you're using standard libraries.

Geolocation and edge config

Vercel exposes the visitor's country in request headers automatically. To preserve this on Coolify, put Cloudflare in front of your VPS and turn on the CF-IPCountry header in their dashboard. Your application code reads req.headers['cf-ipcountry'] instead of req.geo.country. Edge Config doesn't have a direct equivalent, the closest pattern is reading flags from a Redis instance with low TTL, which is a few lines of code.

None of these are dealbreakers for most apps. They're just things to think through before you start clicking around.

Step 1, prepare your Vercel project for export

Vercel doesn't have a single export-everything button, but there are three artifacts you need before you start.

Pull your environment variables

From the Vercel CLI on your local machine:

vercel env pull .env.production --environment=production
vercel env pull .env.preview --environment=preview

This downloads your env vars for each environment into local .env files. You'll paste these into Coolify in a moment. Pay attention to which vars start with NEXT_PUBLIC_ (these need to be available at build time so they're inlined into the client bundle) and which don't (runtime only).

Note your custom domains and DNS

From the Vercel dashboard, list every custom domain on the project. For each, write down which DNS provider it lives on, the current A or CNAME record value and if it's set up with Vercel's automatic Cloudflare integration. You'll need this for the cutover.

Identify your build and start commands

Look at your Vercel project settings under General. Note the framework preset (usually Next.js, sometimes overridden), the build command (default next build), the output directory (default .next), the install command (default npm install or whichever package manager Vercel detected). For 99% of projects these are the framework defaults and you don't need to copy them, Coolify's Nixpacks build pack picks the same defaults. Note them anyway in case you have customizations.

Check for vercel.json

If your repo has a vercel.json at the root, open it. Most fields don't apply outside Vercel (deployment regions, function memory, route rewrites that use Vercel's syntax), but a few do. Custom HTTP headers can be moved into next.config.js using the headers() async function. Redirects can move to the same place using redirects(). Crons need to become Coolify Scheduled Tasks (we'll set this up after deploy).

Step 2, set up Coolify and connect your repo

Coolify needs to be running on a VPS. The LumaDock Coolify VPS ships with v4.0.0 pre-installed, dashboard reachable on port 8000 the moment provisioning finishes. If you're installing yourself, follow the official installation docs.

From the Coolify dashboard, set up a Sources entry for GitHub. Click Sources, then Add, then GitHub App. Authorize and install on the org or account that owns your Next.js repo. The GitHub App is the path that unlocks PR preview deployments later, you specifically want this rather than a personal access token.

Create a project, name it whatever (the name you used on Vercel keeps things mentally aligned) and inside the project click Add a new resource, then Private Repository (with GitHub App). Pick your repo, pick your production branch, let Coolify detect the framework. It'll find Next.js in package.json and offer the Nixpacks build pack.

Step 3, configure environment variables and the build

Open the application in Coolify, go to Environment Variables, click Bulk Edit. Paste your .env.production contents. Before saving, audit each line.

For variables starting with NEXT_PUBLIC_, leave both Is build variable and Is runtime variable checked. These get inlined into the client bundle and need to be present at build time.

For variables that don't start with NEXT_PUBLIC_ (database URLs, API secrets, JWT keys), uncheck Is build variable. They only need to be available at runtime in the Node.js server. This also avoids the multi-line secret problem where Coolify tries to inject a private key at build time and confuses the Dockerfile parser.

Add NODE_OPTIONS=--max-old-space-size=3072 as a build variable if you're on a 4 GB VPS or smaller. Next.js production builds eat memory and a 2 GB box will OOM without this flag plus a swap file. The heap memory fix guide has the full explanation.

Save the env vars. Don't deploy yet, we still need to think about the database.

Step 4, migrate your database

If you were using Vercel Postgres, run vercel env pull if you haven't already so you have the connection string, then take a dump from the Vercel Postgres before it disappears. The simplest path is to use pg_dump against the connection string Vercel gave you:

pg_dump "$VERCEL_DATABASE_URL" --no-owner --no-acl -F c -f vercel.dump

The -F c flag produces a custom-format dump that's compressed and restorable with pg_restore. Inside Coolify, create a PostgreSQL resource (project → Add a new resourceDatabasePostgreSQL). Pick the matching version, accept the auto-generated credentials, click Start.

Then restore the dump from your local machine, the simplest path is to expose the Coolify Postgres on a temporary public port, run pg_restore over that port from your laptop and close the port when done. Or SCP the dump onto the VPS and restore from a temporary container on the Coolify Docker network. Both methods work, the public-port path is faster for small databases.

Update your DATABASE_URL environment variable in Coolify to point at the internal hostname of the Postgres resource (the resource name, not localhost). The format is postgresql://user:password@postgres-resource-name:5432/dbname.

If you were using Vercel KV, spin up a Coolify Redis resource the same way and update REDIS_URL to point at it. KV is just Redis with a Vercel-flavored client library, the underlying protocol is identical.

If you were using Vercel Blob, the path of least resistance is to keep using something S3-compatible (Cloudflare R2, Backblaze B2, Wasabi or self-hosted MinIO) and change your storage client to point at the new endpoint. Your code probably already used @vercel/blob, swap it for the AWS SDK with the right endpoint URL.

Step 5, deploy and verify before DNS changes

Click Deploy. Coolify pulls your repo, runs Nixpacks (or your Dockerfile if you have one) and starts the container. The build streams live in the Deployments tab.

The first build is the slowest. Subsequent builds use the Docker layer cache and complete in 60 to 90 seconds for a typical Next.js app. While the build runs, watch for the install step finishing without errors and the next build step completing without an OOM. If you hit OOM, you didn't add the NODE_OPTIONS variable, see step 3.

Once the deploy succeeds, your app is reachable at the default Coolify subdomain (which Coolify shows you on the application's General tab). Hit that URL and verify the basics. Pages render, dynamic routes work, API routes respond, database queries return real data, sessions persist across requests.

Specific things that often break on the first deploy and weren't obvious before. Image-heavy pages can be slow if sharp isn't installed (add it to dependencies, not devDependencies). API routes that used process.env.VERCEL_URL need to use a Coolify-equivalent variable or your custom domain. Cookies set with the __Secure- prefix need HTTPS, which works on the production domain but not on the IP-based default subdomain unless you've added a domain in Coolify.

Step 6, set up PR preview deployments

One of the things you don't want to lose moving off Vercel is the per-PR preview URL. Coolify supports this through the GitHub App you set up in step 2.

In your application's settings, find the Preview Deployments section. Toggle it on. Coolify will need a wildcard subdomain to generate per-PR URLs, something like *.preview.yourdomain.com. Add a wildcard A record in your DNS pointing at your VPS IP, then enter the wildcard pattern in Coolify's preview deployment settings.

From this point on, every pull request opened against your production branch will spin up a new preview deployment with a unique subdomain. Coolify posts the URL as a comment on the PR (the GitHub App permissions you authorized include this). When the PR is merged or closed, Coolify tears down the preview environment.

One detail Vercel handles automatically that you have to think about on Coolify, preview deployments share the same database as production by default. If your PRs run schema migrations, you'll want a separate preview database to avoid breaking production. Set up a second Postgres resource in your project and add a DATABASE_URL_PREVIEW variable that the preview environment uses. Coolify lets you scope env vars to preview deployments specifically, which prevents preview vars from leaking into production.

The dedicated PR preview deployments guide goes deeper into the wildcard DNS, the GitHub App permissions and the resource-limits gotcha (set per-preview limits or a runaway PR build can OOM your VPS).

Step 7, cut over your custom domain

This is the moment of truth. In Coolify, go to your application's Domains tab and add your real production domain. Save. Now go to your DNS provider and update the A record to point at your VPS IP instead of Vercel's.

Lower your TTL to 60 or 300 seconds at least 24 hours before the cutover so the change propagates fast. Make the DNS change. Within minutes, traffic starts hitting your VPS instead of Vercel. Coolify's Traefik kicks off the Let's Encrypt HTTP-01 challenge and issues a certificate within a minute or two. Watch the Logs tab for ACME success.

If you had Cloudflare in front of Vercel, leave Cloudflare in place and just update the origin record to point at your VPS. Set the proxy status to DNS only (gray cloud) for the cutover so Let's Encrypt can validate. Once the cert is issued, switch to Proxied (orange cloud) if you want Cloudflare's CDN benefits. Set Cloudflare's SSL/TLS mode to Full (strict) and you're production-clean.

Keep the Vercel project running for at least a week post-cutover. Some clients cache DNS aggressively (corporate networks, mobile carriers, occasional bad routers). Traffic that still hits Vercel will succeed during the overlap, you just don't want to delete the project before all DNS resolvers have caught up.

Step 8, recreate Vercel-specific features that ported over

A few things probably worked on Vercel without you having to think about them and now need a tiny bit of attention on Coolify.

Vercel Cron Jobs become Coolify Scheduled Tasks. In the application's settings find Scheduled Tasks, add each cron entry from your vercel.json with the same cron expression and the URL or command. Coolify wakes up the container at the scheduled time and runs it.

Vercel Analytics and Speed Insights become whatever you wire up. The simplest replacement is Plausible Analytics or Umami, both of which Coolify has as one-click services. Spin one up, paste the script tag into your Next.js layout and you're collecting analytics within an hour. The numbers won't match Vercel's exactly because the methodologies differ, but you'll get the same trends.

Vercel's automatic OpenGraph image generation through @vercel/og works fine on Coolify. The library uses Satori under the hood and runs in standard Node.js, no edge runtime required. The only thing to watch is that the OG image generation can be CPU-heavy at request time, so cache the rendered images aggressively.

What it costs and what to expect post-migration

For most Next.js sites moving off Vercel, the monthly bill drops to flat VPS pricing. A 4 GB Coolify VPS at LumaDock runs $6.99 a month. The same Vercel project at moderate traffic (1 million requests, 100 GB bandwidth) starts around $20 plus overage and grows from there.

The trade-off is that you now own the operational layer. The VPS will need security updates (apt updates monthly, Docker bumps occasionally), Coolify itself updates with a single CLI command but you have to remember to run it, backups need to be configured (the database backups guide covers this end to end). The Node.js production security guide covers the server hardening bits that aren't on by default.

For solo developers and small teams the math is good. For large teams with no operations capacity it's worth being honest, you'll spend a few hours a month on the infrastructure that you weren't spending on Vercel. That's still a lot less than the difference in bills, but it's not zero.

Your idea deserves better hosting

24/7 support 30-day money-back guarantee Cancel anytime
Cycle de facturation

1 GB RAM VPS

$3.99 Save  25 %
$2.99 Mensuel
  • 1 vCPU AMD EPYC
  • 30 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Gestion du pare-feu
  • Suivi serveur gratuit

2 GB RAM VPS

$5.99 Save  17 %
$4.99 Mensuel
  • 2 vCPU AMD EPYC
  • 30 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Gestion du pare-feu
  • Suivi serveur gratuit

6 GB RAM VPS

$14.99 Save  33 %
$9.99 Mensuel
  • 6 vCPU AMD EPYC
  • 70 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Gestion du pare-feu
  • Suivi serveur gratuit

AMD EPYC VPS.P1

$7.99 Save  25 %
$5.99 Mensuel
  • 2 vCPU AMD EPYC
  • 4 GB RAM mémoire
  • 40 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Sauvegarde auto incluse
  • Gestion du pare-feu
  • Suivi serveur gratuit

AMD EPYC VPS.P2

$14.99 Save  27 %
$10.99 Mensuel
  • 2 vCPU AMD EPYC
  • 8 GB RAM mémoire
  • 80 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Sauvegarde auto incluse
  • Gestion du pare-feu
  • Suivi serveur gratuit

AMD EPYC VPS.P4

$29.99 Save  20 %
$23.99 Mensuel
  • 4 vCPU AMD EPYC
  • 16 GB RAM mémoire
  • 160 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Sauvegarde auto incluse
  • Gestion du pare-feu
  • Suivi serveur gratuit

AMD EPYC VPS.P5

$36.49 Save  21 %
$28.99 Mensuel
  • 8 vCPU AMD EPYC
  • 16 GB RAM mémoire
  • 180 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Sauvegarde auto incluse
  • Gestion du pare-feu
  • Suivi serveur gratuit

AMD EPYC VPS.P6

$56.99 Save  21 %
$44.99 Mensuel
  • 8 vCPU AMD EPYC
  • 32 GB RAM mémoire
  • 200 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Sauvegarde auto incluse
  • Gestion du pare-feu
  • Suivi serveur gratuit

AMD EPYC VPS.P7

$69.99 Save  20 %
$55.99 Mensuel
  • 16 vCPU AMD EPYC
  • 32 GB RAM mémoire
  • 240 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Sauvegarde auto incluse
  • Gestion du pare-feu
  • Suivi serveur gratuit

EPYC Genoa VPS.G1

$4.99 Save  20 %
$3.99 Mensuel
  • 1 vCPU AMD EPYC Gen4 AMD EPYC Genoa 4ᵉ génération 9xx4 à 3,25 GHz ou équivalent, basé sur l’architecture Zen 4.
  • 1 GB DDR5 mémoire
  • 25 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Sauvegarde auto incluse
  • Gestion du pare-feu
  • Suivi serveur gratuit

EPYC Genoa VPS.G2

$12.99 Save  23 %
$9.99 Mensuel
  • 2 vCPU AMD EPYC Gen4 AMD EPYC Genoa 4ᵉ génération 9xx4 à 3,25 GHz ou équivalent, basé sur l’architecture Zen 4.
  • 4 GB DDR5 mémoire
  • 50 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Sauvegarde auto incluse
  • Gestion du pare-feu
  • Suivi serveur gratuit

EPYC Genoa VPS.G4

$25.99 Save  27 %
$18.99 Mensuel
  • 4 vCPU AMD EPYC Gen4 AMD EPYC Genoa 4ᵉ génération 9xx4 à 3,25 GHz ou équivalent, basé sur l’architecture Zen 4.
  • 8 GB DDR5 mémoire
  • 100 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Sauvegarde auto incluse
  • Gestion du pare-feu
  • Suivi serveur gratuit

EPYC Genoa VPS.G5

$44.99 Save  33 %
$29.99 Mensuel
  • 4 vCPU AMD EPYC Gen4 AMD EPYC Genoa 4ᵉ génération 9xx4 à 3,25 GHz ou équivalent, basé sur l’architecture Zen 4.
  • 16 GB DDR5 mémoire
  • 150 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Sauvegarde auto incluse
  • Gestion du pare-feu
  • Suivi serveur gratuit

EPYC Genoa VPS.G6

$48.99 Save  31 %
$33.99 Mensuel
  • 8 vCPU AMD EPYC Gen4 AMD EPYC Genoa 4ᵉ génération 9xx4 à 3,25 GHz ou équivalent, basé sur l’architecture Zen 4.
  • 16 GB DDR5 mémoire
  • 200 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Sauvegarde auto incluse
  • Gestion du pare-feu
  • Suivi serveur gratuit

EPYC Genoa VPS.G7

$74.99 Save  27 %
$54.99 Mensuel
  • 8 vCPU AMD EPYC Gen4 AMD EPYC Genoa 4ᵉ génération 9xx4 à 3,25 GHz ou équivalent, basé sur l’architecture Zen 4.
  • 32 GB DDR5 mémoire
  • 250 GB NVMe stockage
  • Bande passante illimitée
  • IPv4 & IPv6 inclus La prise en charge d’IPv6 n’est actuellement pas disponible en France, en Finlande ou aux Pays-Bas.
  • 1 Gbps réseau
  • Sauvegarde auto incluse
  • Gestion du pare-feu
  • Suivi serveur gratuit

Frequently asked questions

How long does a Vercel to Coolify migration actually take?

For a single Next.js app with a Postgres database, the practical end-to-end time is about 4 to 6 hours of focused work plus a 24-hour DNS propagation buffer. Set up Coolify (1 hour if it's not pre-installed), connect Git source and create the project (15 minutes), pull env vars and migrate the database (1-2 hours depending on database size), deploy and smoke test (1 hour), set up preview deployments (30 minutes), DNS cutover (15 minutes plus propagation). Bigger apps with multiple databases, custom build configurations or complex monorepos take longer.

Stop installing. Start shipping.

LumaDock Coolify plans come with the dashboard pre-installed, unmetered bandwidth and a flat monthly bill. Try the server risk free with a 30-day refund guarantee.

GPU products are in high demand at the moment. Fill the form to get notified as soon as your preferred GPU server is back in stock.