This is the one migration that starts with a question rather than a checklist.
Kuberns runs long-running container processes. Vercel runs framework builds, serverless functions, and a static edge network. For a backend, a worker, or a server-rendered application that wants to stay up, that difference works in your favour. For a project built around edge execution and provider-specific features, some of it should probably stay where it is.
So the first job is deciding what moves. Do that before you create anything.
Start with an assessment
Answer these about your project:
- Does it need a process that stays up? Background jobs, websockets, long requests, in-memory state, a queue consumer. If yes, Kuberns is a natural home for it.
- How much of it is serverless-specific? Edge middleware, edge-runtime routes, and anything relying on per-request isolation behaves differently on a single long-running server.
- Where does your data already live? Most Vercel projects use an external managed database. If yours does, there may be no data migration at all.
- Do you depend on Vercel product features? Image optimization, their cron, their analytics, and their storage integrations are platform features, not portable code.
- Who consumes your static frontend? A marketing site served from an edge network is not obviously better off on a container.
Three honest outcomes
Most teams land in one of these, and it is worth naming yours out loud.
Move everything. A server-rendered application with jobs, a database, and no edge dependency. This is the common case for backends and full-stack applications, and the rest of this page is written for it.
Split it. Backend, workers, and data services move to Kuberns; the static or edge-heavy frontend stays on Vercel and calls the new API. This is a legitimate destination, not a failed migration.
Stay. A purely static site, or an application built specifically around edge execution, gains little. Kuberns is a poor fit for that, and saying so early saves a week.
What maps directly
| On Vercel | On Kuberns |
|---|---|
| Project | A service inside a project |
| Production branch | An environment |
| Preview deployments | Additional environments, one per branch rather than per pull request |
| Framework preset and build | Detected by the AI agent |
| Environment variables per environment | Environment variables, scoped per environment |
| External database integration | Keep it as-is, or move to a managed datastore |
| Custom domains | Custom domains with automatic SSL |
| Runtime logs | The environment's logs |
What does not move
- Edge middleware and edge-runtime routes. These need to run on the Node runtime instead. Middleware usually still works as ordinary server code; anything relying on edge-specific APIs does not.
- Serverless function semantics. On Kuberns your code runs in one continuous process. Anything that assumed a fresh isolate per request, or used the filesystem as scratch space between invocations, needs review.
- Provider image optimization. This is a platform feature. It needs a library, an external service, or pre-built images.
- Vercel Cron. Scheduled work becomes an in-application scheduler inside a worker, or stays external.
- Preview deployments per pull request. Kuberns environments are branch-based. You get preview environments, but per branch rather than per PR.
Before you start
Collect:
- The repository, the production branch, and the root directory if it is a monorepo.
- Every environment variable, for all three Vercel environments. They differ, and the differences matter.
- Your build command and output directory.
- The database and any storage integrations, with their connection strings.
- Custom domains and their current TTLs.
- Your cron schedules.
Do not remove the Vercel project. It is your rollback until Step 6 is verified.
Step 1: Prepare a long-running start command
This is the one code-level change most Vercel projects need. Your application must start a server that stays up and listens on the port Kuberns provides.
web: next start -p $PORTThe exact command depends on your framework, but the shape is the same: a production server that runs continuously and reads its port from the environment rather than hard-coding one.
Confirm this works locally before going further. Build the application, run the production start command, and load it in a browser. If that does not work on your machine, it will not work on Kuberns.
Step 2: Connect the repository
Create the service from your Git provider and select your production branch. Deploy it as a non-production environment first, on the Kuberns-provided URL. Your live Vercel deployment is unaffected.

For a monorepo, note the root directory before you start.
Step 3: Check what the agent detected
The agent reports the framework, root directory, dependency file, base image, web port, build commands, and process commands.

Two fields deserve a second look on a Vercel migration:
- Web port. Your process must listen on the port the agent reports.
- The start command. Detection may propose a build-and-serve command rather than the production server command from Step 1. Correct it here.
See agent failures if the result is wrong.
Step 4: Recreate variables and provision resources
Add your environment variables, matching key names exactly, including case. Take them from your Vercel Production environment, not Development.
Two things to watch:
- Build-time versus runtime variables. Framework-prefixed public variables are baked in at build time. If one changes, a redeploy is required, not just a variable update.
- Integration-injected values. Anything a Vercel integration supplied automatically will not be in your own variable list. Collect those from the integration.

If you are keeping an external database, your existing connection string carries over unchanged and there is nothing to migrate. If you are moving the database onto Kuberns, create it from the environment's Resources tab.

Connection details for a managed database live on its datastore overview page. If you are importing data, load your dump with the standard client for that database, as described in the Heroku guide. Kuberns does not restore a dump into a running datastore for you.
Environment variables apply on the next deploy, and saving them triggers one automatically.
Step 5: Validate before cutting over
Work through the test environment on its Kuberns URL.
- The application boots and stays up. A process that exits after responding is the classic serverless-to-container failure.
- Server-rendered pages, API routes, and any middleware behave as they did.
- Scheduled work now actually fires, wherever you moved it.
- Static assets and images load.
- Outbound integrations and webhooks reach the new environment.

Watch memory as well as correctness. A continuous process accumulates what a fresh isolate per request used to discard.
Step 6: Move the domain
Lower your DNS TTL a day ahead, to something short such as 300 seconds, and wait for the old TTL to expire. Rollback speed is set entirely by that decision.
Then add the hostname under the environment's Custom Domains and point DNS at the target Kuberns shows you.
Subdomain CNAME app -> <Kuberns hostname shown in the dashboard>
Root domain A @ -> <server IP shown in the dashboard>
The domain moves through DNS verification, SSL provisioning, and activation. See DNS, SSL, and activation if it stalls.
Rollback
Keep the Vercel project deployed until you are confident. With a short TTL, rolling back is pointing DNS back at Vercel.
If you kept your database external, rollback stays clean for as long as both platforms can reach it, which is a real advantage of the split approach.
Common problems
The process starts and then exits. The start command builds or renders and finishes instead of serving. It needs to be a production server that stays up.
The application is unreachable although the deploy succeeded. It is listening on a hard-coded port instead of the one the environment provides.
A public variable has the wrong value. Build-time variables are baked in at build. Redeploy rather than only updating the value.
Middleware behaves differently. It was running on the edge runtime and is now ordinary server code. Edge-specific APIs need replacing.
Images are unoptimized or failing. Provider image optimization does not migrate and needs a library or external service.
Scheduled jobs never run. Vercel Cron is platform configuration and does not travel with the repository.