deplaneDocs Dashboard

Moving from Vercel

Move a Vercel project to Deplane with one command. deplane import vercel reads the project on Vercel and shows what moves and what stays. It then creates the Deplane app with its production variables and a cron job for each Vercel cron, and deploys your code. Vercel keeps serving your users until you switch.

The command runs on your own computer with your Vercel token, which never leaves it. It only reads Vercel: nothing there is changed. The command and its flags are in the CLI reference, and every error has a fix in Troubleshooting and error codes. It works like Moving from Heroku.

Before you start

  1. Install the Deplane CLI and run deplane login.
  2. Have the project's code in a folder: a checkout of the repository Vercel deploys, at the commit it runs. If Vercel builds a subfolder (its Root Directory), pass that folder with --source.
  3. Create a Vercel token: Account Settings → Tokens → Create, scoped to the project's team, with a short expiration.

The Vercel token. A Vercel token can do everything your account can in its scope; there are no read-only tokens. The CLI only reads with it (GET requests to api.vercel.com). Delete it when the import is done.

Give the token to Deplane in one of three ways, never as a flag:

A token piped on stdin wins over VERCEL_TOKEN. The CLI says which one it used, never the token itself. It is never written to disk, never printed, left out of --debug, and never sent to Deplane.

The team. A project that belongs to a team needs the team: put its slug or ID first (my-team/my-app), or set VERCEL_TEAM_ID. Without either, the CLI uses the team in the folder's .vercel/project.json (vercel link writes it), or your personal account.

Secret variables

Vercel never gives back the values of Secret variables (called sensitive before), to anyone: not in the dashboard, the API or vercel env pull. The import lists them by name, copies the others, and creates the app without deploying it, since it would start without them. The next steps show what to set before you deploy:

deplane secrets set STRIPE_SECRET_KEY=... --app my-app
deplane secrets set --build STRIPE_SECRET_KEY=... --app my-app   # if the build reads it too
cd my-app && deplane launch --app my-app   # deploys the app and writes deplane.toml

Take the values from where you keep them: a password manager, or the service that issued them.

Check first

$ deplane import vercel acme/shop --check
Vercel project shop (framework nextjs, team acme, repo acme/shop@main, commit 1a2b3c4) → Deplane app shop

Code
  ✓ Deploys /home/me/shop with Railpack: Detected Next.js 15, Node 22, port 3000.
  ✓ Your folder is at commit 1a2b3c4, the one Vercel runs.
  ✓ Vercel builds this project as Next.js; Railpack builds it too, and Deplane runs it with `next start`.
  ⚠ Next.js on `next start` keeps middleware, API routes, ISR and image optimization ...

Processes
  ✓ web: Vercel runs the project as functions on demand → 1 small instance. Set more with `deplane scale`.
  ✓ cron `0 5 * * *` /api/cron/sync on Vercel → cron job cron-sync, `0 5 * * *` (UTC), on a small instance: ...
  ⚠ Vercel calls a path of the app on each schedule; the Deplane cron jobs make the same request to http://shop/PATH ...

Data
  ✓ Copied as they are, so the app keeps using those databases where they are: DATABASE_URL (ep-cool-name.eu-central-1.aws.neon.tech). ...

Config vars
  ✓ 3 copied as secrets: CRON_SECRET, DATABASE_URL, NEXT_PUBLIC_SITE_URL.
  ✓ 3 also set as build secrets, since Vercel gives every variable to the build too ...
  ⚠ Not copied, Vercel never gives back the values of Secret (sensitive) variables: STRIPE_SECRET_KEY. ...

Domains
  ⚠ www.shop.example points at Vercel (cname.vercel-dns.com). It moves when you switch ...

Plan
  ✓ Fits your Team plan: after the import the team uses 2 of 40 instances and 1 GB of 16 GB memory.

Nothing was changed (--check). Run the command again without --check to import.

✓ is what moves as it is, ⚠ is what you should know or do yourself, and ✗ is what stops the import. --check --json prints the same report as one JSON document. Then run the command again without --check (in a terminal it asks first; from a script, add --yes).

What moves

On VercelOn Deplane
A Next.js projectAn app that Railpack builds and runs with next start: pages, API routes, middleware, ISR and image optimization work there.
A static site (Vite, Create React App, Astro, Gatsby ...)An app that Railpack builds and serves as files.
SvelteKit, Nuxt, Remix, SolidStart, server-rendered AstroAn app, once it builds a Node server: switch from the Vercel adapter to the framework's Node adapter (the report says which).
Production environment variables (Config)Secrets, and build secrets too, since Vercel gives every variable to the build (NEXT_PUBLIC_ ones are built into the pages). Not copied: VERCEL_* and system variables, and variables set only for Preview, Development or a branch.
Secret (sensitive) variablesListed by name, not copied: see Secret variables.
Cron jobs (crons in vercel.json)Cron jobs with the same schedule (UTC on both). Each makes the request Vercel makes, GET on the path, to http://APP/PATH over the private network, with CRON_SECRET as the bearer token only when it is set (with node, or curl for an app without Node). Day and month names are converted; a schedule Deplane cannot run is a ✗ in the report. A cron job the app cannot answer is listed with the command that adds it later, and not created: on a plan where apps sleep (Free), for a path that is a Vercel Function outside Next.js, and for a site that serves only files. Cron jobs turned off on Vercel are not created.
Production domainsListed, and moved at the switch. *.vercel.app stays with Vercel.
Databases and stores you connected (Neon, Supabase, Upstash ...)Their URLs are copied as they are, and the app keeps using them. To move a Postgres database later, use deplane db import.
The codeYour folder, built by Railpack, or by your Dockerfile if it has one.

Instances: Vercel has none to map. The app starts with one small instance (0.5 CPU, 512 MB); a Next.js app often needs medium: deplane scale --size medium.

What does not move

Switch over

  1. Set the Secret variables and deploy, if the import listed any. Test the app at its Deplane address.
  2. Before the day: run deplane domains add HOSTNAME --app APP for each custom domain and add the TXT record it shows.
  3. Disable Vercel's cron jobs (the project's Settings → Cron Jobs → Disable), so they do not run on both. The Deplane cron jobs run from the first deploy, and a cron job cannot be paused: if they must not run twice before the switch, disable Vercel's earlier, or remove Deplane's (deplane processes remove NAME) and add them again now.
  4. Switch DNS to the target deplane domains add showed, and wait for the certificate (deplane domains check HOSTNAME --app APP).
  5. Remove the domains from the Vercel project, and delete it once the app has run well on Deplane.
  6. Delete the Vercel token in Account Settings → Tokens.

Limits

The Heroku import's limits apply: 10 workers and cron jobs per app, sizes up to 2 GB. Secret variables are not copied. The import is built on Vercel's public REST API; tell support@deplane.io if Vercel answers something the CLI does not expect.

This page is also available as Markdown. AI agents can start at /llms.txt.