Postgres · Guide

Migrate your Postgres database to Canner, with little or no downtime.

Two routes: a dump and restore that takes a short outage, or an inbound subscription that follows your old server live so the switch takes seconds. This page helps you choose, then walks through both, the cutover checklist and how to go back.

Which route to take

Dump and restore (canner db migrate-in) is the simplest and works on every Canner plan. Writes to the old database stop while it runs, so the outage lasts as long as the copy. It suits a small database, or one you can take offline overnight.

Follow live (an inbound subscription) copies the existing rows, then streams changes from the old server until you cut over. It needs the dedicated instance (CA$9 a month per project, any paid plan) and a source you can set up for logical replication. Choose it when downtime has to be seconds.

Either way, the source must be reachable from the internet at a public address. A database that only accepts connections from inside a private network will not work until you open it to Canner.

  • Create the Canner database first, on the Postgres version you want (17 or 18, fixed at creation).
  • Check the storage pool: the copy counts toward your organization’s limit. Backups and uploads stop at 100%, and database writes lock at 10% over.
  • List the extensions you use. The dedicated instance offers 14 (pgvector, PostGIS, pg_trgm, pg_cron, hstore and others); postgres_fdw, dblink and file_fdw are not offered.

Route 1: dump and restore with migrate-in

Canner streams the database from the source with no local file, which is why it also suits databases too large to download. It works with any public Postgres server: Supabase, Neon, Heroku, Amazon RDS, Render and others.

# Stream a database straight from a publicly reachable Postgres server
canner db migrate-in --from postgres://user:pass@source.example.com:5432/appdb

Route 2: follow the old server live

With a subscription, the old server keeps taking writes while Canner catches up. You cut over when everything is in step. The steps:

  • Prepare the source. It needs wal_level = logical and a user with the REPLICATION attribute. On a managed service that is a parameter or role setting; the provider’s docs say how. Then create a publication for the tables.
  • Create the tables on Canner first. Logical replication copies rows, not schema. Restore the schema with the same table and column names.
  • Turn on external access for the target so you can connect from your own machine (TLS-only, IP allowlist), and install any extensions your schema needs on the dedicated instance.
  • Add the subscription with the source URL read from an environment variable, so the password is never printed. Canner copies the existing rows, then streams changes. You see how many tables are in step and when the last change arrived. Up to five subscriptions per database.
# On the source: publish the tables (needs wal_level = logical and a user with REPLICATION)
CREATE PUBLICATION app_pub FOR ALL TABLES;

# Copy the schema only: the tables must exist on Canner first
export SRC_URL='postgres://repl_user:pass@source.example.com:5432/appdb'
pg_dump --schema-only --no-owner --no-privileges "$SRC_URL" | psql "$CANNER_URL"

# Follow the source live (URL read from an env var, never printed)
canner db subscriptions appdb add legacy --from-env SRC_URL --publication app_pub

Two behaviours to plan for

Changes are applied with your table owner’s rights, never as a superuser, so triggers on your tables run with your rights only.

Replicated changes also run with an empty search_path. A trigger function must use schema-qualified names, for example public.audit rather than audit. If a change cannot be applied (a missing table, a conflicting row), the subscription shows Failing, you get an alert, and it retries by itself once you fix the cause.

Publications only include the tables you name, and adding tables to a publication later needs a refresh of the subscription. Logical replication does not copy sequence values: check sequences after cutover (next section).

Cutover checklist and rollback

  • Wait until the subscription is in step: every table caught up and the last-change time current.
  • Stop writes on the source. Put the app in maintenance mode or point it at a read-only user, and let the last changes arrive.
  • Check sequences. An auto-increment or identity column would restart from the old value on Canner and collide. Read the current values from the source and set them on Canner with the script below.
  • Check extensions and triggers: every extension is installed, and trigger functions use schema-qualified names.
  • Recreate roles. Dumps carry no owners or privileges, so create the read-only or read-write roles you need and re-issue grants.
  • Remove the subscription. This removes the slot on the source; if the source is already gone, use --force.
  • Point the app at Canner. DATABASE_URL is injected on the next deploy, so redeploy and run your smoke tests.
  • Turn on backups straight away, and consider point-in-time recovery and an off-site copy.
-- Run on the SOURCE. It prints one setval() statement per sequence.
SELECT format('SELECT setval(%L, %s, true);',
              quote_ident(schemaname) || '.' || quote_ident(sequencename),
              last_value)
FROM pg_sequences
WHERE last_value IS NOT NULL;
-- Run the printed statements on the Canner database.

Notes by source

These come from each vendor’s own documentation. Settings and menus change, so follow the vendor’s current guide for the exact steps.

SourceWhat to know
Supabase †Replicating out to an external subscriber is supported, but it needs a direct connection, not the pooler.
Neon †Supports logical replication as publisher, and documents live migration. Note that Neon says enabling it cannot be reverted.
Amazon RDS †Logical replication needs the parameter rds.logical_replication set to 1, and a reboot.
Crunchy Bridge † †Documents logical replication out to an external target, and lists inbound replication as a migration option.
Azure Database for PostgreSQL †Logical replication is native; it needs wal_level=logical and a restart.
Heroku, Render and othersUse the dump route, or export a dump from the provider and load it with canner db import.

† Competitor details come from each vendor’s own published pages on the dates shown; prices and plans change, so check the vendor before you decide. Supabase (2026-09-26) · Neon (2026-09-26) · Amazon RDS (2026-09-26) · Crunchy Bridge (2026-09-26) · Crunchy Bridge (2026-09-26) · Azure Database for PostgreSQL (2026-09-26)

Questions

How long will the downtime be?

With dump and restore, writes to the old database stop for as long as the copy runs, so it depends on the database size. With an inbound subscription the switch itself takes seconds: you stop writes, let the last changes arrive, fix the sequences and repoint the app.

Do I need the dedicated instance?

Only for following a server live. canner db migrate-in and canner db import work on every plan. The dedicated instance is CA$9 a month per project on any paid plan.

Can I migrate from a private network?

Not directly. The source must be reachable from the internet at a public address. Private, loopback and cloud-metadata addresses are refused. Open the source to Canner for the length of the migration, or use a dump and canner db import.

What happens to my sequences?

A dump carries sequence values. A live subscription does not, because logical replication does not copy them. Check sequences after cutover and set them with the setval script on this page.

Will my triggers keep working?

Yes, with two rules: they run with your table owner’s rights, not as a superuser, and they run with an empty search_path, so the functions must use schema-qualified names.

Can I go back if something goes wrong?

Before cutover, remove the subscription and nothing has changed on the source. After cutover, point the app back at the old server, which has the data up to the moment you stopped writes. Use canner db migrate-out to send later writes back.

Does Canner keep my source password?

The subscription URL is read from an environment variable or standard input and never printed, and the password is handed to Postgres. Canner does not keep it. Changes are applied with your table owner’s rights, never as a superuser.

Bring your database home.

Create a free account, make the target database, and try canner db migrate-in on a copy before you plan the real move.