Skip to main content
HostwaresHostwares

Migrating from Vercel to Hostwares: A Complete Guide (2026)

Hostwares Team··11 min read

Before you start: you probably should not do this

Vercel is the best place in the world to run a Next.js application. That is not a polite opening, it is the reason this guide has a long list of things you lose. If any of the following is true, close the tab and stay where you are:

  • You are on the Hobby plan and it is a personal project. Vercel's own FAQ describes Hobby as "for personal, non-commercial use", and it costs nothing. There is no saving to chase.
  • Your team lives on preview deployments. One preview URL per pull request, with comments attached to the rendered page, is a workflow, not a feature. We do not have it.
  • Your traffic is globally distributed and latency-sensitive. Vercel serves from a global edge network. A container on one server in one region does not.
  • You are heavily invested in Edge Middleware, ISR at scale, or their image optimisation pipeline. All three are the parts that translate worst.

The case for moving is narrow and it is about usage-based billing on a workload that is predictable. Vercel Pro is $20 per user per month, with $20 of included usage credit, and then meters a long list of dimensions on top. If your application is a steady-state app with a database behind it, servicing a known amount of traffic, you are paying a metered price for a workload that never varies. That is the case where a fixed monthly container is cheaper and the trade-offs are survivable.

Pricing verified 13 August 2026 from vercel.com/pricing. Every figure below is quoted from that page.

What Vercel actually charges

DimensionHobby (free)Pro ($20/user/month)
Fast Data Transfer100 GB / month included1 TB / month included, then from $0.15 per GB
Edge Requests1M / month included10M / month included, then from $2 per 1M
Function Invocations1M / month includedfrom $0.60 per 1M
Active CPU4 hours / month includedfrom $0.128 per hour
Provisioned Memory360 GB-hrs / month includedfrom $0.0106 per GB-hr
Image Transformations5K / month includedfrom $0.05 per 1K
ISR Reads1M / month includedfrom $0.40 per 1M
ISR Writes200,000 / month includedfrom $4 per 1M
Build machinesnot shownStandard machines at $0.014 per minute
Runtime log retention1 hour1 day, 30 days with Observability Plus

Two caveats about that table. The Pro column shows explicit included allowances only for Fast Data Transfer and Edge Requests; for the other lines the page publishes a unit rate plus the $20 usage credit, not a separate free tier, so what you pay depends on your mix. And "starting at" is Vercel's own wording, because rates vary by region. Do not read these as ceilings. Put your own numbers in the Vercel cost calculator before spending a morning on any of this.

Step 1 — Export your environment variables

The Vercel CLI will pull them for you, per environment. Do it for production explicitly, because the default is your development environment and the values differ:

npm i -g vercel
vercel login
vercel link

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

That writes a KEY="value" file. Three things to fix before you import it anywhere:

  • Remove the VERCEL_* variables. VERCEL_URL, VERCEL_ENV, VERCEL_GIT_COMMIT_SHA and friends are injected by the platform and mean nothing off it. If your code reads VERCEL_URL to build absolute URLs, that is a code change, not a config change. Replace it with your own APP_URL.
  • Replace connection strings that came from a Marketplace integration. Anything Vercel provisioned for you injects its variables into the project. Those need to point somewhere you control before the old project is deleted.
  • Check for values that only exist as secrets. vercel env pull gives you decrypted values for environments you have access to. Anything you cannot pull, you will have to regenerate at the vendor.

Step 2 — Sort out the database, because Vercel does not include one

This is the part people forget. Vercel has no first-party managed Postgres. The old Vercel Postgres product was moved to Neon, and Postgres now arrives through the Marketplace, billed as a separate product. Practically, that means your database was never really part of your Vercel deployment and you have two choices:

  • Leave it where it is. If you run Neon, Supabase or PlanetScale, they are independent services. Point the new deployment's DATABASE_URL at the same database and you have no data migration at all. This is the lowest-risk path and it is usually the right one for the first cutover.
  • Move it to a managed database here, from $3/mo for PostgreSQL, MySQL, MariaDB, Redis or MongoDB with automated backups. Do this as a second, separate change once the application is already running.

If you do move the data, dump and restore with the ownership flags:

pg_dump -Fc --no-owner --no-acl -v -d "$OLD_DATABASE_URL" -f app.dump

pg_restore --verbose --clean --if-exists --no-owner --no-acl \
  -d "$NEW_DATABASE_URL" app.dump

Make a second change at the same time. Serverless functions need pooled connections because every concurrent invocation is a new client, which is why so many Vercel projects carry ?pgbouncer=true, connection_limit=1, or an HTTP-based serverless driver. A long-running container holds one pool for the life of the process, so you can drop the serverless driver, use a normal pg or Prisma connection, and set a sensible pool size. Connection counts usually fall.

Step 3 — Turn functions into a running process

On Vercel, each route is a function that is invoked, runs, and dies. Here, your application is one process that starts and stays up. For a Next.js app that difference is mostly invisible, because next build then next start produces exactly the server Vercel was shimming for you. Set:

Build command:  npm run build
Start command:  npm run start   # next start -p $PORT
Port:           3000

Bind to 0.0.0.0 and read the port from the environment rather than hardcoding it. If you want a smaller image, add output: "standalone" to next.config.js and start from node .next/standalone/server.js.

Several things get better as a side effect, and they let you delete code. There are no cold starts. In-process caching works, so an LRU map in module scope now survives between requests, which it never reliably did across function instances. Background work after the response no longer needs waitUntil. There is no function duration ceiling, so long-running requests and slow report generation stop being a platform problem.

One thing gets worse: a single process means a single blast radius. A memory leak that function recycling used to paper over will now grow until the container restarts. Size the pack with headroom and watch memory for the first week.

Step 4 — What actually breaks

Read this section before you start, not after.

  • Edge Middleware. middleware.ts still runs, but in the Node runtime rather than at an edge POP, so it executes at your origin and adds latency to every request instead of removing it. More importantly, the helpers from @vercel/functions such as geolocation() and ipAddress() return nothing off-platform. If you do geo-routing or country blocking in middleware, rewrite it against x-forwarded-for, or against Cloudflare's cf-ipcountry header if you proxy through Cloudflare.
  • ISR. Incremental Static Regeneration works self-hosted, but the cache is written to .next/cache on local disk. That is fine on a single container and wrong the moment you run more than one, because each replica revalidates independently and serves different content. If you scale out, configure a shared cacheHandler in next.config.js backed by Redis. On-demand revalidation via revalidatePath and revalidateTag keeps working.
  • Image optimisation. next/image off Vercel optimises in-process using sharp. It works, it costs you CPU and RAM on your own container, and it is not their pipeline. Make sure sharp is installed in the production image. If the CPU cost bothers you, either set unoptimized: true and serve pre-sized assets, or point loader at an image CDN.
  • @vercel/* packages. Every one of these is a platform binding. @vercel/analytics and @vercel/speed-insights stop reporting, so self-host Plausible or Umami. @vercel/blob needs an S3-compatible bucket. @vercel/kv becomes a managed Redis. @vercel/postgres becomes pg or Prisma. waitUntil from @vercel/functions becomes an ordinary await. For OG images, Next ships next/og, which is the same renderer without the platform dependency.
  • vercel.json is ignored. Rewrites, redirects and headers move into next.config.js. The crons block has no equivalent in the framework at all, so those become scheduled tasks that call the same endpoints over HTTPS. Add a shared secret header to them, because the routes are now publicly reachable and Vercel is no longer the only caller.
  • maxDuration and runtime: "edge" exports are inert. Harmless, but delete them so nobody is misled later.

If your app is a Next.js application with a database, server components, API routes and no edge middleware, almost none of this applies and the move takes an hour.

Step 5 — Deploy and test on the temporary domain

Connect the same GitHub repository. Framework detection fills in the build and start commands, so for a standard Next.js repo there is nothing to configure. Import the cleaned .env.production, pick a pack, and deploy. Every deployment gets a working subdomain with SSL, so you can exercise the real thing while Vercel still serves live traffic. A Standard pack at $7/mo (1 vCPU, 2 GB, 25 GB) is the right default for a Next.js app with a database; Performance at $18/mo (2 vCPU, 4 GB) is for apps doing image work or heavy SSR.

Test the things that fail quietly:

  • Any route that used to read VERCEL_URL to construct absolute links, including OAuth callbacks and webhook URLs
  • Image-heavy pages, watching container memory while you load them
  • ISR pages, checking they revalidate rather than serving a build-time snapshot forever
  • Anything with an IP allowlist at a third party. New host, new outbound IP.
  • Cron endpoints, now that they are called by a scheduler and not by Vercel

The AI DevOps agent reads build and runtime logs directly, so a failed build here is usually one question rather than an afternoon.

Step 6 — Cut over DNS

The day before: drop the TTL on the records currently pointing at Vercel to 300 seconds. If they sit at 3600 or 86400, this single step is the difference between a five-minute cutover and a day of split traffic, and it only works if you do it in advance.

At cutover:

  1. Add your custom domain to the new deployment and let the certificate issue. Confirm it serves over HTTPS on the real hostname before you touch DNS.
  2. Replace the A or CNAME record that points at Vercel with the record for the new deployment.
  3. Watch both sets of logs. Traffic drains from Vercel over roughly one TTL.
  4. Leave the Vercel project in place for a week. It is your only rollback, and reverting is one DNS change.

If your database stayed where it was, this cutover is genuinely zero-downtime, because both deployments talk to the same database and it does not matter which one a given visitor reaches. That is the main argument for not moving the database in the same change.

What you give up, stated plainly

You lose preview deployments, and there is no substitute for a per-pull-request URL with the reviewer UI on top. You lose the global edge network, so a visitor in Sydney now travels to wherever your container lives. You lose the image optimisation service, instant rollback to a previous immutable deployment, and edge-level DDoS absorption. Vercel's Next.js integration is built by the people who build Next.js, and framework features land there first. None of that is marketing on their part, and no fixed-price container replaces it.

What you get is a bill that does not move when you are linked on Hacker News, a warm process, no duration limit, and control of the runtime.

What this actually costs

The comparison that is fair is a small team on Pro. Three developer seats is 3 × $20 = $60/mo before a single request is served, since Pro is priced per user per month. The equivalent here is a Standard pack at $7/mo plus a managed PostgreSQL at $3/mo, which is $10/mo, and seats are not a billing dimension.

The comparison that is not fair is a solo developer on Hobby. That is free, and free is cheaper than $10. Stay on Hobby until the non-commercial restriction or an allowance forces your hand.

Run the real numbers, from Vercel's published rates rather than a guess, in the Vercel cost calculator.

Related

Ready to deploy?

Start free on Hostwares - your app live in 60 seconds.

Get Started Free