--resume) and a read-only MCP tool, and it survives a restart of the control plane.
Open it in the dashboard under Settings, Import. Read the migration overview first for the flow and the downtime table.
How far to trust this
No real Coolify, Dokploy or CapRover instance was available while this was built. The wizard was exercised against fixture servers shaped from each platform’s documented API, with fake credentials, plus unit and API tests. That proves the job logic, the read-only guarantee (the fixture servers reject every non-GET), resumability and the safe-to-delete rules. It does not prove that a field name or route matches your version of the old platform. Run Test connection and a plan against your own instance first, and compare two or three apps you know well before you rely on a result.The steps
Nothing in any step stops, edits or deletes anything on the old instance. To go back at any point before the first write lands here, point the DNS record at the old server again.
Credentials
- The source credential is sent in a request body, kept in server memory for the session (for a limited time set by
APP_MIGRATE_HUB_PASSWORD_TTL) and wiped when the session is forgotten or expires. It is never written to the database, the logs or the audit log, and no response echoes it. - After a restart of the control plane the credential is gone but the job is not. The wizard asks for the token again and continues.
- Jobs whose source is an SSH login or a pasted file cannot be reconnected from the CLI. Reconnect them in the dashboard.
Resuming a job
A job is an import session. Everything it did is stored, so you can stop at any point, restart the control plane, and carry on. What is re-run is safe to re-run: staging skips apps that already exist, and a build interrupted by a crash shows as retryable instead of staying “building”.--retry stages again the items that failed (or verifies again the ones a restart interrupted) and reconnects the source first when it has to. --retire exits 1 until the old instance is safe to delete, so a script can wait on it. levelrail-cli import apps --from dokploy --url URL --token-stdin --test runs the connection test alone.
The safe-to-delete checklist
A gate that has no evidence yet is not checked, never green. The live gates only run when you press Run the live checks (or pass
--probe), because they touch the network. Reading the checklist from the API or the MCP tool never does.
If something goes wrong the checklist also prints the rollback guidance: before the first write lands here a rollback is a DNS change. After a database takes writes here, copy the data back to the old database first, or those writes are lost. Stop the old instance and keep it stopped for a few days before you delete it.
API
All routes are under/api/v1/migration/apps. Every route that carries or uses the source credential needs the write-sensitive ability.
The event stream polls stored state at the interval set by
APP_MIGRATE_EVENTS_INTERVAL (default one second) and sends a keep-alive every APP_MIGRATE_EVENTS_HEARTBEAT. Probe timeouts come from APP_MIGRATE_PROBE_TIMEOUT.
AI agents
get_migration_job_status is a read-only MCP tool. It reports the phase, progress, failed items with their reasons, the next steps and which safe-to-delete gates are open. It never runs a probe and cannot change a job. Text written by the source (app names, error reasons) is untrusted input.
What it does not do yet
- Environments of one Coolify project share one project here.
- Database data is copied by a command you run or by the data copy API, not by the staging button, and a database that takes writes during the final copy needs a write pause you arrange.
- Volume copies marked by hand are taken at your word. Only the SSH volume copy records file and byte counts.
- Network-level facts of the old platform (custom Docker networks, team members, notification channels) are listed as invisible in the gap report, not migrated.
- Nothing here has run against a real production instance of the old platforms.