Migrate from Vercel

Last updated: June 24, 2026

Vercel is a great place to start a Next.js app. But somewhere past the free tier — a spike in serverless invocations, image-optimization charges, bandwidth overages, a function timeout you can't tune — the bill stops matching the value, and the platform starts deciding things for you. This recipe moves your app to a server you own on American Cloud, where the cost is predictable and the runtime is yours.

You don't do the Linux part. With the American Cloud MCP server connected to your AI assistant, the assistant reads your repo, maps every Vercel feature to its American Cloud equivalent, prices the move so you can compare it against your real Vercel bill, provisions the server, deploys, and walks you through a careful DNS cutover that keeps Vercel serving traffic until you're confident.

This is the same deployment engine as Deploy a Next.js app with your AI assistant — read that first if you want the underlying mechanics. This page is about doing it to an app that's already in production somewhere else, which mostly means: inventory carefully, and cut over without downtime.

Provisioning and DNS changes are write operations. You'll need a read-write API key from console.americancloud.com/api-keys and the --allow-writes flag on the MCP server. See the overview for setup and safety. The inventory phase below is fully read-only — you can do all of it with a read-only key before committing to anything.

[ claude code · migrate in one conversation ]
The assistant prices the American Cloud equivalent first, then builds it on your approval — your old provider stays up until you cut over.

What this looks like

The migration runs as a guided conversation in five phases. Phases 1 and 2 are read-only — your assistant inspects and plans, nothing is created or billed. Phases 3 through 5 do the actual move.

  1. Inventory — the assistant reads your repo and your Vercel config and produces a migration map.
  2. Plan and price — it proposes the American Cloud equivalent and a cost estimate to set against your Vercel bill.
  3. Provision and deploy — it builds the server and ships your app (leaning on the deploy recipe).
  4. Map the features — custom domains, env vars, cron jobs, blob storage, and serverless routes each get a home.
  5. Cut over — lower DNS TTL ahead of time, deploy, verify against the new server, switch DNS, then decommission Vercel once you're sure.

Do it in a Claude Code session: that client combines the American Cloud tools with your terminal, so the same conversation can read the repo, provision the VM, and run the deploy steps over SSH. Cursor and the other clients work too — you'll just run the SSH steps yourself when prompted.

Phase 1: inventory your app (read-only)

Before moving anything, get an honest picture of what Vercel is actually doing for you. Some of it is your app (a next.config, your routes); some of it is Vercel platform features (a vercel.json, environment variables, cron entries, custom domains) that need an explicit home on the new server. Open your project and paste this.

text
I'm planning to migrate this Next.js app off Vercel to a VM I own on American
Cloud. Don't change or create anything yet — this is a read-only inventory pass.
 
Read the repo and build me a migration map:
 
1. Read next.config (js/ts/mjs) and tell me: the output mode (default,
   "standalone", or "export"), any image domains / remotePatterns, redirects,
   rewrites, headers, and anything that assumes the Vercel runtime.
2. Read vercel.json if it exists. List every cron entry, rewrite, redirect,
   header, and any function/region settings.
3. List the routes that are serverless or edge functions (app/api/* route
   handlers, middleware.ts, any "edge" runtime exports). Note anything that
   uses the Vercel-specific request/response or KV/Blob/Postgres SDKs.
4. Read package.json: Node version, build and start scripts, and whether the
   build is memory-hungry.
5. Make a checklist of the environment variables this app reads (scan for
   process.env.* usage). I'll supply the values — do NOT ask me to paste
   secrets into the chat; just list the names.
6. Note any custom domains the app serves on (from my notes or config) and
   whether the app uses Vercel Blob, Vercel KV, or a hosted Postgres.
 
Output a single migration map: what moves as-is, what needs a server-side
equivalent, and what I need to provide (env values, domain list, DB dump).

What your assistant will do

This phase touches your filesystem only — no MCP write tools, no API calls that cost anything.

  • Reads your code. It opens next.config, vercel.json, package.json, middleware.ts, and your app/api route handlers directly from the repo.
  • Classifies each piece. Static export vs. standalone server changes the whole plan (see the next phase). Edge/serverless routes become normal routes on a long-running server. Cron entries in vercel.json become scheduled jobs on the VM.
  • Builds the env-var checklist by scanning for process.env usage, so nothing silently goes missing on the new server. It lists names, never asks you to paste secret values into the chat — you'll put those on the server directly.
  • Flags storage. If the app uses Vercel Blob or KV, those map to American Cloud object storage. If it uses a hosted Postgres, that becomes PostgreSQL running on the VM (more on both below).

The output is a plain-language map you can sanity-check before a single resource exists.

Phase 2: plan and price (read-only)

Now turn the map into a concrete American Cloud plan with a number attached — before creating anything. The MCP server's cost-estimate tools are read-only, so the assistant can price the whole setup and you can lay it next to your Vercel invoice.

text
Based on the migration map, propose an American Cloud setup and price it.
Don't create anything yet.
 
- If my app builds with "standalone" output (a normal Next.js server), plan a
  single VM: recommend a region near my users, a current Ubuntu LTS image, and
  the smallest VM package that can build and run this app.
- If my app is a static "export", plan the smallest VM tier — no Node process
  to run, nginx serves the exported files directly.
- List the regions, images, and VM packages so I can see the options.
- Then call the cost-estimate tool for the VM and show me the hourly and
  monthly numbers. Add a public IP if one's needed, and object storage if the
  migration map calls for it.
- Give me a single monthly total I can compare against my Vercel bill.

What your assistant will do

  • Picks the shape from the inventory. A standard Next.js app (default or output: "standalone") becomes one long-running server: it calls list_regions, list_images filtered to Ubuntu, and list_vm_packages to find a region and a small compute tier within the package's CPU/memory limits.
  • Simplifies for static exports. If your app is output: "export" (or a plain static site), there's no Node process to run — nginx serves the exported files directly, so the smallest VM tier is plenty and there's one less moving part to operate.
  • Prices it before building. It calls get_cost_estimate_vm with the exact region, package, size, and image (plus get_cost_estimate_public_ip, and get_cost_estimate_object_storage if the plan includes object storage for Blob or KV data) and shows the monthly figure. Nothing is billed until you say go.

This is the comparison that matters. American Cloud bills a flat rate for the server you choose — not per serverless invocation, per image transform, or per GB of bandwidth. Put the assistant's monthly estimate next to your last few Vercel invoices and decide with real numbers. (For the why behind this, see Escaping vendor lock-in.)

Phase 3: provision and deploy

With the plan approved, the build-and-deploy itself is exactly the flow documented in Deploy a Next.js app with your AI assistant — provision a VM, open ports 22/80/443, install Node and nginx over SSH, run the standalone build as a systemd service behind nginx, and turn on HTTPS with Let's Encrypt.

The one difference for a migration: don't point your live domain at the new server yet. You want to deploy and fully test against the VM's IP first, while Vercel keeps serving your real traffic. So run the deploy recipe through the build and HTTPS steps, but hold the DNS switch for Phase 5. The "execute the migration" prompt below wires this together end to end.

Phase 4: map the Vercel features

Most of a Vercel migration is translating platform features into things that run on your own server. Here's how each one maps, and which MCP tools or server-side steps your assistant uses.

Vercel featureOn American CloudHow
Custom domainsHosted DNS zone + recordscreate_dns_zone, create_dns_record (A record at the VM's public IP); update your registrar's nameservers
Environment variablesServer environment / systemd unitWritten into the app's env file or the systemd service over SSH — values go on the server, never into chat
Cron jobs (vercel.json)cron or systemd timersThe assistant writes a systemd timer (or crontab entry) per cron route over SSH
Image optimizationHandled by the Next.js standalone servernext/image optimizes at runtime on your server; no per-transform billing
Vercel Blob / KVObject storagecreate_object_storage_unit, create_object_storage_bucket, get_object_storage_keys — S3-compatible; see object storage
Serverless / edge functionsRoutes on the long-running serverapp/api route handlers and middleware run in the same Next.js process — often simpler: no cold starts, no per-invocation pricing
Hosted PostgresPostgreSQL on the VMInstalled over SSH, bound to localhost; migrate data with pg_dump / pg_restore

A few of these are worth a closer look.

Serverless and edge functions

On Vercel, each app/api route or piece of middleware is deployed as an isolated function that spins up per request. On your own server, they're just routes in the one long-running Next.js process. Nothing in your code has to change — the standalone server handles them. In practice this is usually simpler: no cold starts, no invocation limits, no per-call billing. If a route relied on a Vercel-specific runtime API, your assistant flags it in Phase 1 so you can swap it for the standard Node equivalent.

Cron jobs

Vercel cron entries are just a schedule pointing at a route. Your assistant reads them from vercel.json and recreates each one as a systemd timer (or a crontab line) on the VM that hits the same route on the same schedule — over SSH, so they survive reboots.

Blob and KV storage

If your app stores files in Vercel Blob, your assistant creates an S3-compatible object storage unit and bucket (create_object_storage_unit, create_object_storage_bucket), fetches the access keys (get_object_storage_keys), and updates your app to talk to it with any S3 client. The full walkthrough is in Object storage with your AI assistant. Key-value usage typically becomes a small store on the server (for example Redis installed over SSH alongside the app).

A hosted database

If you're on Vercel Postgres or another hosted database, your assistant installs PostgreSQL directly on the VM over SSH, bound to localhost so it's never exposed to the internet, and migrates your data with pg_dump from the old database and pg_restore into the new one. Ask for it explicitly:

text
This app uses a hosted Postgres. On the VM, install PostgreSQL listening only
on localhost, create a database and user for this app, and put the connection
string in the app's environment file. Then walk me through dumping my current
database with pg_dump and restoring it here with pg_restore, and verify the row
counts match before I cut over.

Phase 5: cut over without downtime

This is the part that's unique to migrating a live app. The goal: bring the new server fully online, prove it works, and only then move traffic — with Vercel still up as your safety net.

Lower your DNS TTL first — a day or two ahead if you can. TTL is how long resolvers cache your DNS records; a high TTL means a cutover takes hours to take effect everywhere. Drop it to something short (60 seconds) before the migration so that when you flip the record, traffic moves fast and a rollback is just as quick. Your assistant can do this on an American Cloud zone, or tell you what to change at your current DNS provider.

Test against the new server before you touch DNS. Your assistant can hit the VM's public IP directly with the right Host header — e.g. curl -H "Host: your-domain.com" https://VM_IP/ --resolve your-domain.com:443:VM_IP — so it sees exactly what visitors will see, while real DNS still points at Vercel. Or it can add a temporary line to your local hosts file mapping your domain to the VM's IP, so you can click through the whole site in a browser before any public change. Ask: "verify the migrated site against the VM's IP with my domain's Host header, and check every route the inventory found."

Here's the prompt that runs the migration end to end and ends on a careful cutover:

text
Execute the migration to American Cloud using the plan and prices we agreed on.
Narrate each step and pause before anything destructive or anything that moves
real traffic.
 
1. Provision the VM per the deploy-nextjs recipe: small Ubuntu VM, my SSH key,
   ports 22/80/443 open. Wait until it's STARTED with a public IP.
2. Deploy this repo: Node LTS + nginx, standalone production build, run as a
   systemd service behind an nginx reverse proxy.
3. Recreate my environment variables on the server (I'll give you the values to
   put in the env file directly — not in chat). Recreate each vercel.json cron
   entry as a systemd timer.
4. If the inventory found Blob/KV or a hosted database, set up object storage
   and/or PostgreSQL-on-the-VM and migrate the data as we discussed.
5. Provision a Let's Encrypt certificate so the VM serves HTTPS for my domain,
   even though DNS doesn't point here yet (use the DNS-01 path or a temporary
   verification as needed).
6. Before any DNS change: verify the site against the VM's IP using my domain's
   Host header. Walk every route from the inventory. Show me the results.
7. When I confirm it's good: lower the DNS TTL if it isn't already, then switch
   the A record for my domain to the VM's public IP.
8. Watch resolution until my domain points at the VM, then confirm the live
   site loads over HTTPS. Leave my Vercel deployment running untouched.

What your assistant will do

  1. Builds and deploys exactly as in the deploy recipe: create_vm with networkAccess to open 22/80/443 and keypairs for your SSH key, polling get_vm until STARTED, then Node, nginx, the standalone build, and a systemd service over SSH.
  2. Restores your config. Env vars go straight into the server's env file or the systemd unit; cron entries become timers. Storage and database data move per Phase 4.
  3. Gets HTTPS ready early so the new server can serve your domain over TLS before traffic arrives.
  4. Verifies against the IP. Using a Host-header curl or a temporary hosts entry, it checks every route the inventory found — all while Vercel still serves your users.
  5. Cuts over deliberately. Only on your confirmation does it switch the A record (update_dns_record on an American Cloud zone, or it tells you the change to make at your DNS provider) to the VM's public IP, then watches resolution until your domain points at the new server.
  6. Leaves Vercel running. Because you lowered the TTL, rollback is fast: if anything looks wrong, point the record back at Vercel and you're restored in seconds.

Decommission Vercel — when you're sure

Give it a day or two. Watch the new server's traffic and error logs, confirm cron jobs are firing, check that uploads land in object storage. When you're confident the new server is carrying everything Vercel used to, then — and only then — tear down the Vercel deployment. There's no rush: keeping it up a little longer costs little and buys you a clean rollback the whole time.

text
The migrated site has been healthy for a couple of days. Confirm the VM is
handling traffic, the systemd timers (former crons) have run on schedule, and
nothing is still calling Vercel. Then give me a checklist for safely removing
the Vercel project.

Next steps