Sync any database, anywhere.
A single binary that turns the painful, error-prone sprawl of pg_dump → pg_restore shell scripts into a guided, observable workflow — with named profiles, integrity-checked dumps, and server-to-server streaming, across multiple database engines.
- One CLI, many databases. Postgres, MySQL, and MariaDB all work today (MySQL and MariaDB share a common
_mysqlcommonbackend). The driver interface is engine-agnostic, so SQLite, MongoDB, SQL Server, and ClickHouse can follow. - Native, not reimplemented. siphon shells out to
pg_dump/pg_restore,mysqldump/mysql, andmariadb-dump/mariadbfor the actual data movement — you inherit 20+ years of correctness from the official tools, wrapped in a consistent UX. - Integrity by default. Every dump is checksummed (SHA-256) and recorded in a sidecar metadata file.
siphon verifyre-hashes the dump and flags corruption or tampering — and fails with a distinct exit code so CI can catch it. - Built for scripts and humans. A Cobra command tree with predictable flags and POSIX exit codes for automation; an interactive Bubble Tea dashboard when you invoke
siphonbare. - Named profiles + secret refs. Store connection details once; with a secret ref like
env:VAR,keychain://<account>(OS credential store), orawssm://<id>#<key>(AWS Secrets Manager), the password is resolved at runtime instead of being stored in config. (A value with no scheme is a literal, so don't commit a plaintext password.) - Streaming sync.
siphon sync src dstpipes a backup straight into a restore with no intermediate file on disk.
- Multi-engine, native tooling. PostgreSQL, MySQL, and MariaDB, each driven by the official client tools (
pg_dump/pg_restore,mysqldump/mysql,mariadb-dump/mariadb). TheDriverinterface is engine-agnostic, so more engines can follow. - Core workflow.
backup,restore,sync,verify,inspect, and adumpscatalog — driven by namedprofiles and a single config file. - Streaming sync.
siphon sync src dstpipes a backup straight into a restore through a bounded buffer — no intermediate file, with backpressure and failures propagated end to end. - Incremental backup.
backup --incremental --base <id>captures a bounded change set since a base via Postgres logical decoding or MySQL/MariaDB binlog;restorereplays the base→incremental chain in order — see docs/INCREMENTAL.md. - Cross-engine sync.
sync --cross-engineintrospects the source schema into a canonical model and maps types across engines (e.g. Postgres → MySQL) — see docs/CROSS_ENGINE.md. - CDC (continuous replication).
siphon cdc/sync --continuoustails the source's change stream and applies it to the target, with a snapshot→stream handoff, resumable state, same- and cross-engine — see docs/CDC.md. - Integrity by default. Every dump is SHA-256 checksummed in a sidecar;
siphon verifyre-hashes and fails with a distinct exit code so CI catches corruption or tampering. - Cloud storage. Keep the dump catalog locally or in an S3 / S3-compatible bucket via a pluggable
storage.Storebackend (storage:config) — see docs/STORAGE.md. - Retention. Chain-aware pruning (
siphon dumps prune) with keep-last-N / max-age / GFS rules and per-profileretention:config — see docs/RETENTION.md. - Operational controls. An append-only audit log of destructive ops, 2FA/group gating (typed confirmation and/or TOTP), opt-in aggregate telemetry,
siphon schedule(recurring backups via crontab), andsiphon tunnel(SSH local-forward via a bastion) — see docs/OPS.md. - Secret references. Resolve passwords at runtime via
env:,keychain://(OS credential store), orawssm://(AWS Secrets Manager) instead of storing them in config. - Scripts and humans. A predictable Cobra command tree with POSIX exit codes for automation, plus an interactive Bubble Tea dashboard (profiles · dumps · jobs) when you invoke
siphonbare. - Easy to install, signed. Cross-platform binaries published via a tag-triggered release with SHA-256 checksums and cosign-keyless signatures, a checksum-verifying
curl | shinstall script, and docs at siphon.nixrajput.com.
-
Go 1.26 or newer — only needed to build from source; prebuilt binaries are available via the install script, Homebrew, and Scoop (see Install).
-
Database client tools — siphon shells out to the native dump/restore tools; it does not embed a client. You only need the tools for the engines you actually use:
- PostgreSQL profiles need
pg_dump,pg_restore,psql. - MySQL profiles need
mysqldump,mysql. - MariaDB profiles need
mariadb-dump,mariadb(the renamed binaries shipped by MariaDB 10.5+; older installs that only shipmysqldump/mysqlare not yet supported).
Platform PostgreSQL MySQL / MariaDB macOS brew install postgresql@16brew install mysql-client/brew install mariadbDebian/Ubuntu sudo apt install postgresql-clientsudo apt install mysql-client mariadb-clientFedora/RHEL sudo dnf install postgresqlsudo dnf install mysql mariadbWindows Install the EDB PostgreSQL package and add its bin/toPATHInstall the MySQL / MariaDB client and add to PATH - PostgreSQL profiles need
-
Docker (optional) — only needed to run the integration test suite (
make test-integration).
The install script is live as of
v1.0.0. The Homebrew tap and Scoop bucket activate once their tap repos + tokens are provisioned; until then, use the install script or build from source.
Linux / macOS — the install script downloads the right release binary and verifies its SHA-256 before installing:
curl -fsSL https://raw.githubusercontent.com/nixrajput/siphon/main/scripts/install.sh | shOverride the target with SIPHON_INSTALL_DIR=… or pin a version with SIPHON_VERSION=v1.0.0. The docs site lives at siphon.nixrajput.com.
Homebrew:
brew install nixrajput/siphon/siphonScoop (Windows):
scoop bucket add siphon https://github.com/nixrajput/scoop-siphon
scoop install siphonPrebuilt binaries for every OS/arch are attached to each release, with a checksums.txt and a cosign keyless signature. Verify provenance — pin the issuer and the signer identity, or a forged Fulcio cert would still pass:
cosign verify-blob \
--certificate checksums.txt.pem \
--signature checksums.txt.sig \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--certificate-identity "https://github.com/nixrajput/siphon/.github/workflows/release.yml@refs/tags/v1.0.0" \
checksums.txtSubstitute the tag you downloaded for v1.0.0. Then check a binary's archive against the verified checksums.txt.
From source:
git clone https://github.com/nixrajput/siphon.git
cd siphon && make build
./bin/siphon --versionThis produces ./bin/siphon; move it onto your PATH (e.g. sudo install -m 0755 bin/siphon /usr/local/bin/siphon).
# 1. Register a connection profile (secrets via env: refs, never plaintext in config)
export PROD_DB_PASS='…'
siphon profile add prod \
--driver postgres \
--host db.example.com \
--user app_user \
--password 'env:PROD_DB_PASS' \
--database app_prod \
--sslmode require
siphon profile list # show saved profiles
# 2. Inspect the schema (tables, row estimates, on-disk sizes)
siphon inspect prod
# 3. Back it up — written to ~/.local/share/siphon/dumps/ with a checksummed sidecar
siphon backup prod
siphon dumps list # newest first
# 4. Verify integrity (re-hashes the dump against the recorded checksum)
siphon verify <dump-id>
# 5. Restore into another profile
siphon restore --profile staging --dump <dump-id> --clean
# 6. Stream prod → staging directly, no intermediate file
siphon sync prod stagingExit codes follow a POSIX-friendly taxonomy (0 ok, 1 user error, 2 system error, 3 integrity failure, 130 cancelled) so siphon backup prod && upload and CI pipelines behave correctly.
| Command | Description |
|---|---|
siphon backup [profile] |
Dump a database to a checksummed file in the catalog |
siphon restore [dump-id] |
Load a dump into a database (--clean to drop-and-recreate) |
siphon sync [from] [to] |
Backup + restore in one streamed pass |
siphon verify <dump-id> |
Re-hash a dump and check it against its recorded checksum |
siphon inspect <profile> |
Show tables, row estimates, and sizes for a profile |
siphon dumps list|inspect|prune |
List, inspect, or prune saved dumps |
siphon profile add|list|show|rm |
Manage named connection profiles |
siphon config path|edit |
Show or edit the config file |
siphon schedule add|list|remove |
Manage cron-scheduled recurring backups |
siphon tunnel <profile> |
Open an SSH tunnel to a DB via its bastion |
siphon (bare) |
Launch the interactive multi-panel dashboard |
Run siphon <command> --help for full flags.
siphon reads a YAML config from an XDG-compliant path. Find it with siphon config path:
- Linux:
$XDG_CONFIG_HOME/siphon/config.yaml→~/.config/siphon/config.yaml - macOS:
~/.config/siphon/config.yaml - Windows:
%APPDATA%\siphon\config.yaml
Override the location with SIPHON_CONFIG_HOME. A profile entry looks like:
version: 1
defaults:
dump_dir: ~/.local/share/siphon/dumps # where backups + sidecars are stored
jobs: 4
profiles:
prod:
driver: postgres
host: db.example.com
port: 5432
user: app_user
password: env:PROD_DB_PASS # resolved from $PROD_DB_PASS at runtime
database: app_prod
sslmode: requireSecret references are resolved at runtime, which keeps the password out of the config file when you use one. Supported schemes: env:VAR (environment variable), keychain://<account> or keychain://<service>/<account> (OS keychain — macOS Keychain / Windows Credential Manager / Linux Secret Service), and awssm://<secret-id> or awssm://<secret-id>#<json-key> (AWS Secrets Manager; enable with secrets.awssm: true). A value matching no scheme is treated as a literal — so a plaintext password lives in the file and should not be committed. See docs/OPS.md.
By default the dump catalog lives on local disk at defaults.dump_dir. To store dumps in an S3 / S3-compatible bucket instead, add a storage: block:
storage:
type: s3 # "local" (default) | "s3"
bucket: my-siphon-dumps # required for s3
prefix: prod # optional key prefix
region: us-east-1
endpoint: "" # optional: custom endpoint for MinIO / R2Credentials are resolved from the standard AWS chain (env vars, ~/.aws, instance role) — never stored in the config file. See docs/STORAGE.md for details.
A retention: block (default + optional per-profile override) drives siphon dumps prune, which deletes old backups as whole chains so an incremental is never orphaned:
defaults:
retention:
keep_last: 7
max_age: 720h # 30 days
gfs: { daily: 7, weekly: 4, monthly: 6 }siphon dumps prune is dry-run by default; pass --apply to delete. Flags override the configured policy per run. See docs/RETENTION.md for details.
siphon is a strictly layered Go application; imports flow downward only, enforced at lint time by golangci-lint's depguard (an upward import fails CI):
cmd/siphon entry point (one-line main)
│
internal/cli internal/tui presentation (Cobra · Bubble Tea) — siblings
└──────┬───────┘
internal/app application verbs (backup, restore, sync, …)
│
internal/driver/<engine> database adapters (postgres; mysql/mariadb in v1.0)
│
config · secrets · profile · dumps · jobs · errs domain + support packages
- Drivers are compile-time Go packages that shell out to native tools for data movement and use a client library (pgx) for fast schema reads.
- Dumps live on disk as
<id>.dumpwith a<id>.meta.jsonsidecar (profile, driver, size, SHA-256 checksum, timestamp). - Jobs run long operations on a goroutine and stream progress
Events that the CLI heartbeat (and, later, the TUI) renders.
make help # list all targets
make build # produce ./bin/siphon
make run # go run ./cmd/siphon (launches the TUI on bare invoke)
make test # unit tests
make test-integration # integration tests against a real Postgres (needs Docker)
make lint # golangci-lint, incl. depguard layer enforcement
make tidy # go mod tidy
make clean # remove bin/ and dist/Tests run race-clean (go test -race ./...). The integration suite is gated behind the integration build tag and spins up postgres:16-alpine via testcontainers.
See CONTRIBUTING.md for the full contributor guide and SECURITY.md for reporting vulnerabilities.
1.0 ships the full feature set above. Beyond it:
- More storage backends — Google Cloud Storage and Azure Blob, on the existing pluggable
storage.Storeseam. - More engines — the engine-agnostic
Driverinterface leaves room for SQLite, MongoDB, SQL Server, and ClickHouse.
Ideas and requests are welcome — open an issue.
Contributions are welcome. Please read CONTRIBUTING.md, keep changes within the layered architecture (depguard will tell you if you stray), and make sure make test and make lint pass before opening a PR.
Adding a new database engine? See docs/DRIVERS.md for the driver contributor guide.
Concept docs: docs/INCREMENTAL.md (incremental backup + restore), docs/CROSS_ENGINE.md (cross-engine sync + the type-map matrix), and docs/CDC.md (continuous CDC sync, same- and cross-engine). All three work end-to-end; live DB behavior is integration-tested in CI.
siphon is free and open source. If it saves you time, you can support its continued development — every bit helps and is genuinely appreciated. ❤️