sluice

Migrating from Neon with sluice

Direct vs -pooler endpoints (and why CDC needs the direct one), the irreversible enable_logical_replication project setting, TLS interop, and the live-validated migrate + continuous-sync recipe.

Neon is managed Postgres, so sluice drives it with the vanilla postgres engine — no flavor, no special driver. It has been live-validated as a migration and CDC source (Neon → PlanetScale Postgres, 2026-07-15): fidelity was byte-identical on md5 ground truth including the hard value families — NaN inside numeric[], ±Infinity, denormal floats, and 2-D arrays with NULL elements — and the snapshot → CDC handoff and post-handoff convergence were clean. What is Neon-specific is the endpoint model and how logical replication gets enabled. This guide covers both.

Direct vs pooler endpoints — pick by workload #

Every Neon branch has two hostnames for the same database:

EndpointHostname shapeWhat it is
Directep-<name>-<id>.<region>.aws.neon.techA real Postgres backend connection.
Pooledsame, with a -pooler suffix on the first labelpgbouncer in transaction mode.

Enabling logical replication (the project setting, not postgresql.conf) #

Neon defaults to wal_level=replica. sluice's CDC preflight checks this before touching any slot and refuses loudly — the message points at the provider matrix in Prepare a Postgres source. The fix on Neon is not a GUC edit: it's the project setting enable_logical_replication (console: Settings → Logical replication; also settable via the project-update API). Two things to know before you flip it, both validated live:

Bulk migrate does not need it — only continuous sync (a replication slot) does.

The validated recipe #

One-shot copy (dry-run first, then drop the flag):

sluice migrate \
    --source-driver postgres --source 'postgres://user:[email protected]/neondb?sslmode=require' \
    --target-driver postgres --target 'postgres://user:pass@target-host:5432/app?sslmode=require' \
    --dry-run

Continuous sync — direct endpoint, after enabling logical replication:

sluice sync start \
    --source-driver postgres --source 'postgres://user:[email protected]/neondb?sslmode=require' \
    --target-driver postgres --target 'postgres://user:pass@target-host:5432/app?sslmode=require' \
    --stream-id neon-app

Connection notes from the validation run:

The wal_proposer_slot you'll see in slot listings #

Every Neon endpoint carries an always-present physical replication slot named wal_proposer_slot — it's part of Neon's safekeeper architecture, not a leaked consumer. sluice's slot-health monitoring correctly ignores it. If you enumerate slots with your own tooling (or sluice slot list), expect to see it and leave it alone; only sluice_-prefixed logical slots belong to sluice.

What sluice checks for you #

Next steps #