kisenon

Region migration

Move a project to a different region — what migrates, the managed flow, and the manual pg_dump runbook that works today.

Region migration moves an existing project from the region it was created in to a different one. You'd reach for it when your traffic has shifted closer to another region (lower round-trip latency), or when a compliance or data-residency requirement says your data must live in a particular jurisdiction.

The migration changes where your data lives, not what it is. Your branches, roles, databases, and the rows inside them all come across. The one thing that changes on the client side is the host in your connection string — your project lands on a new endpoint host in the destination region, so your DATABASE_URL has to be repointed once the cutover lands.

How it works

A managed migration runs as a controlled, validated copy with an explicit cutover you approve. The stages:

  1. Freeze — the source project is briefly put into a read-only / suspended state so the copy has a consistent, non-moving target.
  2. Dump — a logical dump of every branch is taken from the source region.
  3. Transfer — the dump is moved to the destination region over TLS.
  4. Restore — the dump is restored into a freshly provisioned project in the destination region.
  5. Validate — the destination is checked for byte-equivalence against the source: schema fingerprint, per-table row counts, and content checksums must all match before the migration is offered for cutover.
  6. Confirm — nothing switches automatically. You review the validation results and explicitly confirm the cutover.
  7. Cutover — the project's active endpoints are repointed to the destination region. The connection-string host changes.

If you cancel before the cutover, or if validation fails at any stage, the migration rolls back: the destination scaffolding is discarded and the source project is taken out of its read-only state, untouched.

Size guidance

The read-only window scales with the size of your data:

  • Under 10 GB — typically completes in under 15 minutes.
  • 10–100 GB — an extended window; plan for a longer read-only period and schedule it outside peak hours.
  • Over 100 GBcontact support for an assisted migration. Large projects are migrated with a hands-on runbook rather than the self-service flow.

Managed migration (console)

Managed region migration is rolling out. The wizard described here is being enabled progressively; if you don't yet see Migrate region in your project settings, use the manual runbook below, which works on every project today.

The console wizard walks the flow above:

  1. Open the project and go to Settings → Migrate region.
  2. Select destination — pick the target region from the dropdown. The current region is shown for reference.
  3. Review impact — the wizard summarises what's about to happen: the read-only window the project will see, and the fact that the connection-string host changes at cutover.
  4. Monitor progress — each branch shows its own progress through dump → transfer → restore. The wizard streams status as the migration runs.
  5. Review validation — when the copy is complete, the validation results are shown per branch: schema fingerprint match, row-count match, and checksum match.
  6. Confirm switch — once validation is green, confirm the cutover. This is the point of no automatic return.
  7. Update DATABASE_URL — after cutover, copy the new connection string from the endpoint card and update your application's DATABASE_URL. The host has changed; everything else is the same.

Manual migration runbook

This runbook works today, on any plan. It uses standard Postgres tooling and the public connection strings, so it has no dependency on the managed flow. The shape is: stand up a new project in the target region, copy the data in with pg_dump / pg_restore, verify, then repoint and delete the old project.

1. Create the destination project

Create a new project in the target region (console New project, or the API). Match the source project's Postgres major version. Note the new project's connection string from the endpoint card.

2. Dump the source

Dump from the source project's connection string in the custom format. --no-owner and --no-privileges keep the dump portable across the freshly created roles in the destination:

pg_dump \
  --format=custom \
  --no-owner \
  --no-privileges \
  "postgresql://app:SOURCE_PWD@ep_SOURCE.kisenon.com:5432/main?sslmode=require" \
  --file=migration.dump

3. Restore into the destination

Restore into the destination project's connection string. --single-transaction plus --exit-on-error makes the restore all-or-nothing: if anything fails, the destination is left clean rather than half-loaded:

pg_restore \
  --no-owner \
  --no-privileges \
  --single-transaction \
  --exit-on-error \
  --dbname "postgresql://app:DEST_PWD@ep_DEST.kisenon.com:5432/main?sslmode=require" \
  migration.dump

4. Verify

Confirm the destination matches the source before you cut over. Compare per-table row counts against both connection strings:

SELECT relname, n_live_tup
FROM pg_stat_user_tables
ORDER BY relname;

For a stronger check, spot-check content checksums on the tables that matter most. Run this against both the source and the destination and compare the results:

SELECT md5(string_agg(t::text, '' ORDER BY t)) AS checksum
FROM my_table AS t;

Matching row counts and checksums mean the data came across intact.

5. Cut over and clean up

Repoint your application's DATABASE_URL to the destination connection string. Once you've confirmed the application is healthy against the new project, delete the old project to stop billing for it:

keon projects delete <old-project-id>

Deleting a project is irreversible — only do this after you've verified the destination and switched all traffic to it.

FAQ

How much downtime should I expect?

For a managed migration, the only disruption is the read-only window during the copy — writes are paused, reads continue. The window scales with data size (see size guidance): under 15 minutes for projects below 10 GB, longer for larger ones. For the manual runbook, the downtime is whatever window you choose to stop writes for while you dump, restore, and verify.

Can I cancel a migration?

Yes — any time before the final cutover. Cancelling discards the destination scaffolding and returns the source project to normal; the source is never modified until you confirm the switch, so a cancel leaves you exactly where you started.

What happens to my branches?

Every branch is migrated. Be aware that a logical dump-and-restore flattens copy-on-write history: each branch comes across with its current data, but the fork-at-LSN relationship between a child branch and its parent is not preserved — the destination branches start fresh from the migrated data rather than sharing pages. The data is intact; the shared-storage lineage is not.

Do my passwords and roles survive?

Roles are recreated as part of standing up the destination project, and the data they own comes across. Because the manual runbook dumps with --no-owner --no-privileges, role ownership and grants are not carried by the dump — you reapply them on the destination. Treat role/password parity as something to verify and re-establish after the migration, not as automatic. The managed flow recreates the project's roles for you, but the same caution applies: confirm your application's login role and password work against the destination before cutover.

Do my connection strings change?

Yes — the host changes, because your project moves to a new endpoint host in the destination region. You update DATABASE_URL (and any other place the host is hard-coded) once, at cutover. Your API keys (nsk_…) are account-scoped and are not affected by a region migration.

Is my data encrypted in transit?

Yes. The transfer between regions runs over TLS, and both the dump from the source and the restore into the destination use the standard sslmode=require Postgres connections described in Connection strings.

  • Regions — the catalog you migrate between.
  • Projects — the unit that migrates as a whole.
  • Connection strings — the wire format whose host changes at cutover.
  • Branches — copy-on-write children, and how dump/restore affects their lineage.