From Heroku Postgres
Tested with: Heroku preset: offline fixtures (detection of ec2 and Aurora-backed hosts, checklist) · zb migrate 0.1
Heroku Postgres moves to Databasezy PostgreSQL with a copy during a short maintenance window. Heroku does not allow logical replication to outside targets.
| Status | Coming soon · phase 2 |
|---|---|
| Target engines | PostgreSQL , Valkey |
| How we read it | Connection string, File upload |
| Continuous sync | No, copy only |
| Provider preset | heroku |
Before you start
Section titled “Before you start”- A Databasezy PostgreSQL instance, or use
--create. - The Heroku CLI with access to the app.
- A maintenance window long enough for the copy.
Find the connection string
Section titled “Find the connection string”Run heroku config:get DATABASE_URL -a my-app. Heroku rotates Postgres credentials during maintenance and with
heroku pg:credentials:rotate, so start the migration right after you copy the URL, or create a dedicated credential
with heroku pg:credentials:create so a rotation does not cut the copy off.
Heroku Postgres notes
Section titled “Heroku Postgres notes”- Heroku does not allow logical replication to outside targets; plan a short maintenance window or use a pg_backups export.
The preset detects classic ec2-*.compute-1.amazonaws.com hosts and the Aurora-backed hosts of newer plans, adds
sslmode=require, warns about rotation (heroku.credential_rotation) and blocks copy and sync
(heroku.sync_unsupported).
Migrate
Section titled “Migrate”- Open the target PostgreSQL instance (create one first if you need to) and choose the Migrate in tab.
- Under Source, pick Connection string and paste the URL. The host is recognised as Heroku; you can also pick it from the provider list.
- Run Preflight and work through the checklist. Blocking items must be fixed before the copy starts.
- Start the copy and follow Copy and Verify. Mismatches are listed per table or collection.
- Point your application at the new instance. The Report step keeps the timings and verification results.
# Copy the URL and start right away: Heroku can rotate credentialszb migrate --from "$(heroku config:get DATABASE_URL -a my-app)" --engine postgres --create --dry-runheroku maintenance:on -a my-appzb migrate --from "$(heroku config:get DATABASE_URL -a my-app)" --engine postgres --create
# Or upload a Heroku backup insteadheroku pg:backups:capture -a my-appcurl -o latest.dump "$(heroku pg:backups:url -a my-app)"zb migrate --from ./latest.dump --engine postgres --createcurl -sS https://api.databasezy.com/v1/orgs/$ZB_ORG/instances/inst_abc/migrations \ -H "Authorization: Bearer $ZB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "source": { "kind": "connection_string", "url": "postgres://u1abc:[email protected]:5432/d9xyz", "provider": "heroku" }, "mode": "copy"}'
# Follow progress, preflight report and verificationcurl -sS https://api.databasezy.com/v1/orgs/$ZB_ORG/instances/inst_abc/migrations/mig_123 -H "Authorization: Bearer $ZB_API_KEY"After the copy, update the app with heroku config:set DATABASE_URL=postgresql://... -a my-app and turn maintenance
off. Heroku dynos have no fixed egress IP; if you restrict the Databasezy allow-list, route through a static-IP add-on.
Heroku Key-Value Store (Redis) can be copied the same way into Valkey:
zb migrate --from "$(heroku config:get REDIS_URL -a my-app)" --engine valkey --create.
Verify
Section titled “Verify”Verification runs automatically after the copy and compares source and target: row counts per table, sequence or
AUTO_INCREMENT values, the number of indexes and a schema hash. A missing table or a short row count fails the
migration and lists what differs. Check the result with zb migrate status <mig_id> or the Verify step in the
portal, then run your application’s own smoke tests against the new instance before you switch traffic.
Cutover
Section titled “Cutover”This source is copy only. Writes that reach the source after the copy starts are not carried over, so for a database that changes, stop writes before you start the copy (maintenance mode, or scale writers to zero), run the migration, check verification, then point the application at the Databasezy connection string.
Roll back
Section titled “Roll back”A migration never deletes anything on the source. Until you decommission it, rolling back means pointing the
application back at the source. Writes made on Databasezy after you switched are not on the source; if you need
them, copy them back before switching. Cancel a running migration with zb migrate cancel <mig_id>; partially
restored data stays on the target, so restart with --drop-target or delete the instance.
Troubleshooting
Section titled “Troubleshooting”The copy fails halfway with an authentication error
Section titled “The copy fails halfway with an authentication error”Heroku rotated the credential. Create a dedicated credential with heroku pg:credentials:create and start again.
The restore stops on an extension
Section titled “The restore stops on an extension”Extensions such as pgrouting or plv8 are not shipped on Databasezy. Remove the dependency or exclude the objects.
Preflight cannot connect to the source
Section titled “Preflight cannot connect to the source”Check that the source accepts connections from the egress addresses preflight prints, that the host is the public one and that the password has not been rotated. zb migrate --dry-run shows the exact URL that will be used after any rewrites.
Preflight lists blocking items
Section titled “Preflight lists blocking items”Each item has a machine code and a fix. Nothing is written to the target until every blocking item is resolved; warnings do not block.
For anything else, zb migrate status <mig_id> shows the failing step and its message. How migrations work describes every step.