deplaneDocs Dashboard

Moving from Render

Move a Render web service to Deplane with one command: deplane import render reads the service on Render, with the background workers and cron jobs built from the same repository, shows what moves and what stays, then creates the Deplane app with its secrets, workers, cron jobs and release command, copies the Postgres database, adds a Redis for a Key Value, and deploys your code. Render keeps serving your users until you switch.

The command runs on your own computer with your Render API key, which never leaves it. It only reads Render: 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, which explains the switch-over in more detail.

Before you start

  1. Install the Deplane CLI and run deplane login.
  2. Have the service's code in a folder: a checkout of the repository Render deploys, at the commit it runs. The report shows that commit and whether your folder is at it.
  3. Create a Render API key: in the Render Dashboard, Account Settings → API Keys → Create API Key.

The Render API key. Render has no read-only keys: a key can do everything your account can, in every workspace you belong to. The CLI only reads with it (GET requests to api.render.com). Delete the key when the import is done.

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

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

Let Deplane reach the database

Render's DATABASE_URL is the database's internal address, which only works inside Render. The import copies the database through its external address instead, which Render controls with the database's IP allow list (Networking → Access Control on the database's page):

Without a Deplane login, --check cannot read Deplane's addresses: it says so, and the import checks them before it creates anything.

Check first

$ deplane import render shop --check
Render service shop (web service, region frankfurt, repo github.com/acme/shop@main, commit 1a2b3c4) → Deplane app shop

Code
  ✓ Deploys /home/me/shop with Railpack: Detected Node 22, port 3000.
  ✓ Your folder is at commit 1a2b3c4, the one Render runs.

Processes
  ✓ web: 2 × standard on Render → 2 large instance(s).
  ✓ pre-deploy command → release command `npm run migrate`.
  ✓ shop-worker (background worker): 1 × starter on Render → worker shop-worker, 1 small instance(s): `node worker.js`.
  ✓ nightly (cron job): `0 3 * * *` on Render → cron job nightly, `0 3 * * *` (UTC), on a small instance: `node nightly.js`.

Data
  ✓ Postgres (shop-pg, basic_1gb, Postgres 16): copied into a new Deplane database shop-db ...
  ⚠ Key Value shop-cache (starter): a new Deplane Redis shop-redis ... Its data is not copied ...

Config vars
  ✓ 3 copied as secrets: APP_URL, SECRET_KEY_BASE, SENDGRID_API_KEY.
  ✓ Not copied, Deplane sets them: DATABASE_URL, PORT, REDIS_URL.

Domains
  ⚠ www.shop.example points at Render ... It moves when you switch ...

Plan
  ✓ Fits your Team plan: after the import the team uses 5 of 40 instances and 5.8 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). The flags are the same as for Heroku: --source DIR, --name NAME, --check, --yes.

What moves

On RenderOn Deplane
The web serviceThe app. Instances as on Render (with autoscaling, its maximum). Railpack starts your Procfile's web line or your Dockerfile's CMD; the report warns when that differs from Render's start command.
Background workers built from the same repository, branch and root directoryWorkers, with the same start command and instances.
Cron jobs built from the same repository, branch and root directoryCron jobs, with the same schedule (UTC on both). Day and month names (MON-FRI) and 7 for Sunday are converted to Deplane's numbers; a schedule Deplane cannot run is a ✗ in the report, before anything is created.
The pre-deploy commandThe release command.
Instance typesFree and Starter (512 MB): small. Standard (2 GB): large. Larger: large, with a warning that Deplane has less memory (2 GB at most). See Limits.
Environment variables and linked environment groupsSecrets. The service's own value wins over a group's. A worker's or cron job's variables are added; where one sets a name differently from the web service, the web service's value is used and the report names it. Not copied: RENDER, RENDER_*, IS_PULL_REQUEST, PORT, and the DATABASE_URL and REDIS_URL that Deplane sets.
Render Postgres (DATABASE_URL)A new Deplane database, copied once through the external URL (copy mode), attached as DATABASE_URL.
Render Key Value (REDIS_URL), up to 256 MBA new, empty Deplane Redis (Valkey 8, 256 MB), attached as REDIS_URL.
The codeYour folder, built by Railpack, or by your Dockerfile if it has one.

What does not move

Switch over

The first import is a rehearsal: Render keeps serving, and writes made there after the copy are not in the Deplane database. When the Deplane app works:

  1. Before the day: run deplane domains add HOSTNAME --app APP for each custom domain and add the TXT record it shows. Make sure your plan has room for one more database (the report's Plan section says if it does not).
  2. Stop writes on Render: suspend the web service and its workers and cron jobs (each service's Settings → Suspend Service). Render has no maintenance mode, so the site is down from here until DNS moves.
  3. Copy the data again and move the app to the copy in one release:

``sh deplane db import --name APP-db-final --mode copy --yes # paste the External Database URL at the prompt deplane db switch APP-db-final --from APP-db ``

  1. Switch DNS to the target deplane domains add showed, and wait for the certificate (deplane domains check HOSTNAME --app APP).
  2. Keep the Render services suspended until the app has run well on Deplane, then delete them. Remove Deplane's addresses from the database's allow list.
  3. Delete the rehearsal's database: deplane db destroy APP-db.
  4. Delete the Render API key in Account Settings → API Keys.

Limits

The Heroku import's limits apply: Postgres up to 5 GB and versions as for every Postgres import, a new 256 MB Redis without its data, 10 workers and cron jobs per app, sizes up to 2 GB, and copying the database needs a person logged in to the CLI. The import is built on Render's public API; tell support@deplane.io if Render answers something the CLI does not expect.

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