Getting started
Install sluice, point it at a source and target, and run your first migration and continuous sync.
Install
sluice is a single static binary with no daemon and no SaaS dependency. Install with the Go toolchain:
go install sluicesync.dev/sluice/cmd/sluice@latest
Or run the official container image (multi-arch, distroless):
docker run --rm ghcr.io/sluicesync/sluice:latest --version
Pre-built Linux / macOS / Windows binaries are attached to every tagged release. Verify the install:
sluice --version
sluice engines # list the database engines built into this binary
Prerequisites
- A source and a target database you can reach over the network.
- Engines available out of the box:
mysql,postgres, and theplanetscaleMySQL flavor. Runsluice enginesto confirm what your binary supports. - For continuous sync from Postgres, the source normally needs logical replication (a replication slot). Managed Postgres that blocks slots (e.g. Heroku) can use the slot-less trigger engine instead.
Connecting to your databases
Source and target are passed as DSNs (connection strings). The driver is named separately with --source-driver / --target-driver.
| Engine | DSN format |
|---|---|
mysql | user:pass@tcp(host:3306)/dbname |
postgres | postgres://user:pass@host:5432/dbname?sslmode=require |
DSNs often contain credentials, so you can supply them via environment variables instead of flags:
export SLUICE_SOURCE='root:rootpw@tcp(localhost:3306)/app'
export SLUICE_TARGET='postgres://postgres:pgpw@localhost:5432/app?sslmode=disable'
See Configuration for the full set of environment variables and the optional YAML config file.
Your first migration
A one-shot migration translates the source schema, creates the target tables, bulk-copies rows, then builds indexes and constraints. Always do a dry run first — it reads the source schema and prints the plan without touching the target:
sluice migrate \
--source-driver mysql --source 'root:rootpw@tcp(localhost:3306)/app' \
--target-driver postgres --target 'postgres://postgres:pgpw@localhost:5432/app?sslmode=disable' \
--dry-run
When the plan looks right, drop --dry-run to apply it. If a migration is interrupted, re-run with --resume — state is checkpointed per table on the target, so it picks up where it left off:
sluice migrate --source-driver mysql --source ... --target-driver postgres --target ... --resume
INSERT into a populated table would collide on the primary key). Use --resume to continue a prior run, or read the migrate reference for the recovery flags.Your first continuous sync
Continuous sync captures a consistent snapshot, bulk-copies it, then streams ongoing changes. Streams are identified by a --stream-id so they can resume after a restart:
sluice sync start \
--source-driver mysql --source 'root:rootpw@tcp(localhost:3306)/app' \
--target-driver postgres --target 'postgres://postgres:pgpw@localhost:5432/app?sslmode=disable' \
--stream-id app-prod
From another shell, check freshness or status, and stop the stream cleanly when you're done:
sluice sync status --stream-id app-prod --target-driver postgres --target ...
sluice sync health --stream-id app-prod --target-driver postgres --target ... # cron-friendly exit code
sluice sync stop --stream-id app-prod --target-driver postgres --target ... # drains in-flight changes, then exits
Verify the copy
After a migration or once a stream has caught up, compare source and target:
sluice verify \
--source-driver mysql --source ... \
--target-driver postgres --target ...
verify compares row counts by default and can escalate to per-row hashing — see the verify reference.
Next steps
- Command reference — the full flag set for every command.
- cutover — prime target sequences before switching traffic, so the first post-cutover
INSERTcan't collide. - Configuration — YAML config, env vars, type/expression overrides, and PII redaction.
