CapyDB/ docs
GuidesImports & Migrations

Supported sources

Which Postgres providers CapyDB migrates from, how each one is identified, and what each needs before a near-zero-downtime import will work.

CapyDB imports from any PostgreSQL database it can reach. There is no allowlist of providers, and a source that is not listed below is not a problem - it just gets the generic advice instead of provider-specific advice.

What the list below is actually for is the one question a migration plan turns on: can this source stream its changes? If it can, capydb import --follow copies the database while your application keeps running against the old one, and the cutover is the time it takes to swap a connection string. If it cannot, the migration is a dump and restore inside a maintenance window that grows with the size of the data.

That question is not answered by the provider's documentation. wal_level is a setting, and plenty of people have already changed it in either direction. So CapyDB measures it - capydb migrate scan and the import preflight both read the running server - and uses the table below only to explain what to do about the measurement.

Identification

Providers are identified from the server's own catalogs, not from the hostname:

  • Google Cloud SQL and AlloyDB publish no public hostname at all - you connect to an address or through the Cloud SQL Auth Proxy.
  • Heroku Postgres answers on an ordinary EC2 name (ec2-….compute.amazonaws.com).
  • Anything behind a bastion or a private link arrives as an address.

So the probe looks for provider-owned roles (rds_superuser, cloudsqladmin, azure_pg_admin, supabase_admin, neondb_owner), provider-owned schemas (heroku_ext, Supabase's auth/storage/realtime), provider extensions (neon, supabase_vault, google_columnar_engine), provider GUC namespaces (rds.*, cloudsql.*, alloydb.*, azure.*), and aurora_version(). The report tells you which signals decided the answer, so you can argue with it.

Order matters where providers nest: an Aurora cluster carries every RDS marker, an AlloyDB instance every Cloud SQL marker, and Heroku Postgres runs on RDS underneath. The more specific answer wins, because only the specific answer's remediation works.

The matrix

SourceStreaming importWhat it needs first
SupabaseAvailable by defaultDump from the direct endpoint or the session pooler on port 5432 - the transaction pooler on 6543 cannot serve a consistent dump. See Migrate from Supabase.
NeonOpt-inEnable logical replication for the project in the Neon console. Use the direct endpoint, not a -pooler hostname. See Migrate from Neon.
Amazon RDS for PostgreSQLOpt-inSet rds.logical_replication=1 in the instance parameter group, reboot, then GRANT rds_replication TO <migration role>. See Migrate from AWS RDS.
Amazon Aurora PostgreSQLOpt-inSet rds.logical_replication=1 in the cluster parameter group and reboot the writer. Point the migration at the writer endpoint - a reader cannot create a replication slot.
Google Cloud SQLOpt-inSet the cloudsql.logical_decoding flag to on and restart the instance. The source also has to be reachable from outside your VPC, via an authorized network or a proxy.
Google AlloyDBOpt-inSet the alloydb.logical_decoding flag to on and restart the primary - the flag name differs from Cloud SQL's. AlloyDB's columnar engine and google_* extensions have no equivalent on plain Postgres.
Azure Database for PostgreSQLOpt-inSet the wal_level server parameter to logical and restart, then ALTER ROLE <migration role> WITH REPLICATION and grant it azure_pg_admin. Flexible Server; Single Server is retired.
PlanetScale for PostgresOpt-inConfirm logical replication is enabled for the branch and connect on the direct port - PSBouncer on 6432 pools transactions and cannot serve a consistent dump.
Heroku PostgresNot possibleHeroku offers neither logical replication nor superuser access. Migrate with a dump and restore inside a maintenance window. See Migrate from Heroku.
RenderOpt-inEnable logical replication in the database's settings and restart. Use the external connection string. See Migrate from Render.
RailwayOpt-inSet wal_level=logical on the Postgres service and redeploy. Use the public proxy connection string. See Migrate from Railway.
DigitalOcean, Crunchy Bridge, AivenAvailable by defaultDump from the primary connection details rather than a connection pool.
Timescale CloudOpt-inHypertables are a timescaledb construct and CapyDB does not offer that extension, so hypertables have to become ordinary or natively partitioned tables before the data moves.
Self-managed PostgreSQLDepends on your configwal_level=logical, at least one spare replication slot and WAL sender, and the REPLICATION attribute on the migration role.

Only PostgreSQL sources are covered. A MySQL, MariaDB or Vitess database is a different migration - the storage engine, the type system and the SQL dialect all differ - and not one CapyDB performs.

Things that block a streaming import regardless of provider

Even on a source configured for logical replication, two shapes will stop a --follow import, and both are found by the assessment:

  • Tables with neither a primary key nor a replica identity. Their UPDATEs cannot be replicated. The failure arrives partway through the migration rather than at setup, which is the worst time to find it. Add a primary key, or ALTER TABLE … REPLICA IDENTITY FULL (correct, but it sends the whole previous row per change).
  • No free replication slot. max_replication_slots minus the slots already in use has to leave at least one.

Find out for your database

capydb migrate scan --source-url "$OLD_DATABASE_URL"

Read-only, no account needed, and the connection string never leaves your machine. It reports which provider the server says it is, whether it can stream as connected, and what to do if it cannot - plus the physical inventory that decides how long the copy takes.