Move a Render application to Bex by recreating its services, transferring its configuration and data, and validating the result before changing traffic. A compatible manifest does not migrate a database, disk, hostname, or account.
Bex remains in active development; its upstream project does not yet recommend
production workloads. Start with a rehearsal or non-production application.
Review compatibility before committing to a migration.
For a product-level evaluation first, see Bex vs Render.
When you keep using the bex CLI after cutover, the
CLI reference lists every command with its compatibility grade.
1. Inventory the application
Record services and process commands, runtime versions, repository/branch, build paths, environment variables, secret files and groups, databases, queue contents, persistent files, scheduled jobs, domains, and API integrations. Identify any dependency on unsupported Render features.
Choose a destination Bex workspace with the required capacity and platform services configured. The local operator quickstart is an exploration path; it does not by itself supply a complete hosted platform with identity, builds, backups, and public routing.
2. Validate render.yaml
Keep the filename render.yaml. There is no need to rename it to bex.yml.
Bex supports the same broad services: and databases: structure, but validates
its own pinned schema and supported fields. Do not remove runtime,
buildCommand, or startCommand on the assumption they are ignored.
For example, this Bex Blueprint creates a Docker web service and database.
Replace the repository with your own Dockerfile-based application; it must
listen on 0.0.0.0:$PORT and implement /healthz:
services:
- type: web
name: shop
runtime: docker
repo: https://github.com/acme/shop
branch: main
plan: starter
numInstances: 1
healthCheckPath: /healthz
autoDeployTrigger: off
envVars:
- key: DATABASE_URL
fromDatabase:
name: shop-db
property: connectionString
databases:
- name: shop-db
plan: starter
postgresMajorVersion: "16"Choose a database version and plans appropriate to your source and available Bex capacity; this is an illustrative configuration, not a sizing recommendation. Keep production domains out of the rehearsal manifest.
Do not add port to a Blueprint service: the pinned schema rejects it. The
application should listen on Bex's injected PORT (default 3000). The direct
Kubernetes App resource's spec.port is a different configuration interface.
Check each service's type, runtime, port, health check, root directory, storage,
and scaling. Bex supports native builds, environment groups, generated values,
persistent disks, and pre-deploy commands within their documented constraints.
Unsupported fields fail validation; for example, CI-gated checksPass auto-deploy
is unavailable. Inspect every validation error instead of assuming an ignored
field will have Render behavior.
Use the authenticated dry-run/apply steps in the
Blueprint guide or the agent's validate_bex_yml and
deploy tools in Connect an agent. Validate first and
review the plan before applying. Provisioning remains asynchronous; inspect
all returned resources. Reapplying unchanged content is a no-op, and removing an
entry does not delete the old resource.
3. Transfer configuration and test the application
Populate secrets before allowing real work. Replace source connection strings with returned Bex connections or Blueprint references. A generated secret is a new value: use an intentional transfer for signing keys or credentials that must remain compatible during cutover.
Keep workers, schedulers, and external side effects disabled during rehearsal. Starting both installations against the same queue can process work twice. Use test accounts and a test hostname to verify builds, HTTP responses, private connections, background work, and scheduled runs.
4. Rehearse the data transfer
PostgreSQL
Create an empty destination database. Check major-version compatibility, extensions, encoding, ownership, privileges, and storage capacity. Obtain connections from each platform; use an allowed network path and preserve the TLS settings returned by Bex. Do not weaken certificate verification to make a migration command connect.
For a logical migration, the following transfers one database using PostgreSQL
client tools. Set SOURCE_DATABASE_URL and TARGET_DATABASE_URL securely to
your source and empty destination, respectively:
umask 077
pg_dump --format=custom --file=app.dump "$SOURCE_DATABASE_URL"
pg_restore --exit-on-error --no-owner --no-acl \
--dbname="$TARGET_DATABASE_URL" app.dumpStop if the dump fails; do not restore an incomplete archive. Choose a
pg_dump version that supports the source server and a destination version
compatible with its output. This example omits source ownership/ACLs; explicitly
recreate the roles and grants your application needs. It does not transfer all
cluster-global objects. Review pg_dump
and pg_restore
for version and permission requirements.
A Bex physical export or disk snapshot is not interchangeable with this logical archive. Verify row counts, important queries, sequences, permissions, and application behavior after restoring. Measure the transfer duration to plan the write-freeze window; large or continuously written databases need a separate, rehearsed replication/cutover design. See Postgres for Bex recovery. Practice the dump/restore, grant recreation, and writer-handoff sequence on disposable databases with the Postgres transfer rehearsal.
Queues, caches, and files
Decide whether each Key Value dataset is disposable cache, session state, or a queue that must be preserved. Rebuilding a cache differs from draining work; Bex does not expose a general tenant snapshot-import workflow for Key Value. Choose and test a data-specific transfer strategy before cutover.
Copy persistent files through an application-appropriate export/import workflow. Provision the destination disk and check mount paths, permissions, and completeness. Creating a disk does not copy the Render disk.
5. Cut over traffic and writers
For the simple dump/restore approach, schedule a write freeze and repeat the validated transfer after stopping all source writers: web requests, workers, cron jobs, external integrations, and any administrative scripts. Prevent the new installation from writing until that final restore is complete.
Add the production hostname in Bex and follow its returned
ownership and routing instructions. Review both apex and
www records if paired. Verify TLS and the application response; use the returned
routing target rather than constructing an onbex.co hostname. Account for DNS
caching during the transition.
Enable destination writers once, then monitor errors, latency, queue progress, and data integrity. Keep source resources available for the agreed observation period, with duplicate jobs and writes disabled.
6. Define recovery and retire the source
Before destination writes begin, recovery may be as simple as restoring source routing and workers. After Bex accepts new writes, switching DNS back alone can lose those changes. Decide how to reconcile or transfer them before reverting. An image rollback does not restore application data.
After validation and the observation period, retire source resources explicitly, remove obsolete credentials, and check both platforms for remaining resources. Enable Bex automatic deployments only after the desired Git workflow is verified.
Pointing Render API tooling at Bex
Use the Bex token exchange, destination workspace, and returned Bex resource IDs. Render API keys and resource IDs do not transfer. Test every operation your scripts use, including pagination and errors; changing the base URL is only one part of the migration. GraphQL and MCP also have their own schemas and supported actions. See Render parity.