deplaneDocs Dashboard

Moving from Vercel

Move a Vercel project to Deplane with one command, or from the dashboard (From the dashboard). 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.

From the dashboard

New app → Import from another platform (/import, or /import/vercel with Vercel already picked) does the same import without the CLI or a folder, in five steps:

  1. Connect. Create a Vercel token (Account Settings → Tokens → Create) scoped to the project's team, with the shortest expiration, paste it into the masked field and press Read. Vercel has no read-only tokens: the token can change everything in its scope. Deplane only reads with it (GET requests), inside the request that carries it, and never stores it. Delete the token in the same place when the import is done. For a project that belongs to a team, fill in the team's slug or ID (team_...); leave it empty for a personal account.
  2. Pick. The page lists the projects the token can see in that team (at most 100, with a filter box). Pick the one to import, or type it as project or team/project. A link /import/vercel?ref=NAME fills it in, and a token that sees exactly one project checks it at once. Picking runs the check: the report, nothing created.
  3. Review. The same ✓ / ⚠ / ✗ report as --check, with the Plan section, then Code and name, filled in: the repository Vercel is linked to, with its production branch, preselected when it is among the ones you gave the Deplane GitHub App access to (the match is made only inside your own grants; otherwise the page shows the repository's name and a Connect GitHub link that brings you back). The Deplane app's name is the project's, made a Deplane name, with a suffix when a team already holds it. Import asks for your passkey.
  4. Import. The page follows each step (the app with the production variables Vercel returns, as secrets and as build secrets, and a cron job for each Vercel cron), lists what exists so far, then stops at Set secrets when the project has Secret variables.
  5. Set secrets. Vercel never gives back the values of Secret variables (see Secret variables), so the import waits here, as long as it takes, with one masked field per name the report listed. Take the values from where you keep them, fill them in, and press Set secrets: they go straight to the app's secrets, never through the import. Then Deploy connects the repository and builds, and ends with the live address, the switch-over checklist and the reminder to delete the token. A waiting import does not block your team's next import, and Cancel import ends it.

A failed or cancelled import has Delete what it created: the app this import made, nothing else, after your passkey. Then import again. The rest is as for Heroku's From the dashboard: the code comes from GitHub (previews off), the token is used inside the requests that list, check and start the import and dropped, only you signed in to the dashboard can do it, and a team runs one import at a time.

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, which needs Node 18 or later for its built-in fetch, 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.