CapyDB Docs
GuidesImports & Migrations

Migrate from Neon

Move a Neon Postgres database into CapyDB.

Get the source connection string

In the Neon console: Project → Dashboard → Connect (the "Connection string" panel). Take the direct connection string, not the -pooler one — a logical copy should not run through PgBouncer.

It looks like:

postgres://user:password@ep-xxxx-xxxx.eu-central-1.aws.neon.tech/dbname?sslmode=require

Neon-specific caveats

  • SNI: Neon routes connections by TLS SNI. CapyDB's importer uses standard TLS with SNI, so the plain hostname works. If you ever test the same URL with a very old client and get "endpoint could not be found", that is the SNI issue — irrelevant here, but it explains odd results from other tools.
  • Autosuspend: a scaled-to-zero Neon endpoint takes a moment to wake; the preflight's connection timeout (10s) is usually enough, but retry once if the first preflight fails with a timeout.
  • Branches: the URL identifies one branch's endpoint. Make sure it is the branch you actually want (usually main).
  • Postgres major: check the project's Postgres version in Neon settings. CapyDB targets run Postgres 17; a Neon project on 18+ would fail the version check (no downgrades).

Preflight

capydb import preflight --source-url "postgres://...neon.tech/dbname?sslmode=require"

or dashboard → project → Import → paste URL → Run preflight. Fix anything that fails — size over plan limit, unsupported extensions (Neon projects often have pg_stat_statements enabled, which is on the allowlist; Neon-specific extensions are not commonly present in user databases).

Import

Stop or pause writers on the Neon side (the import is point-in-time; later writes are not carried over — see downtime honesty). Then:

capydb import --source-url "postgres://...neon.tech/dbname?sslmode=require" --recreate --wait

--recreate drops and recreates the target database first, so re-running an import is safe and idempotent in outcome.

After the import

  1. Verify sequences: spot-check SELECT last_value FROM <seq>; for hot tables.
  2. \dx — confirm expected extensions exist on the CapyDB side.
  3. ANALYZE; once for planner statistics.
  4. Cut over env vars (DATABASE_URL pooled, direct URL for migrations), deploy, watch Observability.