Git for your database. Instant, isolated copies of any Postgres database in under 5 seconds.
MirrorDB continuously replicates your Postgres database via logical replication, then creates instant copy-on-write branches using btrfs/ZFS snapshots. Each branch is a fully writable, isolated Postgres instance — perfect for testing migrations, letting coding agents work against real data, or exploring schema changes without risk.
| Metric | Value |
|---|---|
| Branch creation time | ~49ms snapshot + ~3s Postgres startup |
| Branch storage overhead | 0 bytes until you write (copy-on-write) |
| 50 branches of 100GB DB | ~100GB total, not 5TB |
| Test suite | 26 tests, all passing |
| Codebase | 8 crates, ~3,500 lines of Rust |
Your Postgres (Neon, RDS, Supabase, self-hosted)
|
| Logical replication (continuous WAL streaming)
v
MirrorDB Engine (Linux + btrfs/ZFS + Postgres 16)
|
| btrfs subvolume snapshot (~50ms, any size)
v
Branch "dev-test" (writable, isolated, full copy)
Branch "feat-xyz" (writable, isolated, full copy)
|
| Connection proxy routes by branch name
v
psql postgres://mirrordb:pass@localhost:6432/dev-test
- Connect your database:
mirrordb connector create postgresql <url> --name prod - Wait for initial sync (one-time, depends on data size)
- Create branches instantly:
mirrordb branch create dev-test -c prod - Connect and use:
psql postgres://...@localhost:6432/dev-test - See what changed:
mirrordb branch diff dev-test - Clean up:
mirrordb branch delete dev-test
# 1. Start the dev environment
docker compose up -d
# 2. Run the test suite
cargo test --workspace
# 3. Demo: instant btrfs branching
docker exec mirrordb-engine bash -c "
btrfs subvolume create /mirrordb/replicas/demo &&
chown postgres:postgres /mirrordb/replicas/demo &&
su - postgres -c '/usr/lib/postgresql/16/bin/initdb -D /mirrordb/replicas/demo' &&
su - postgres -c \"/usr/lib/postgresql/16/bin/pg_ctl start -D /mirrordb/replicas/demo -o '-p 5500' -l /mirrordb/replicas/demo/logfile\"
"
sleep 2
# Create test data
docker exec mirrordb-engine su - postgres -c "psql -p 5500 -c \"
CREATE TABLE users (id serial PRIMARY KEY, name text, email text);
INSERT INTO users (name, email) VALUES
('Alice', 'alice@co.com'), ('Bob', 'bob@co.com'),
('Carol', 'carol@co.com'), ('Dave', 'dave@co.com');
\""
# Show source data
docker exec mirrordb-engine su - postgres -c "psql -p 5500 -c 'SELECT * FROM users;'"
# INSTANT BRANCH (~49ms)
docker exec mirrordb-engine su - postgres -c "psql -p 5500 -c 'CHECKPOINT;'"
time docker exec mirrordb-engine btrfs subvolume snapshot \
/mirrordb/replicas/demo /mirrordb/branches/my-branch
# Start branch Postgres
docker exec mirrordb-engine bash -c "
chown -R postgres:postgres /mirrordb/branches/my-branch &&
rm -f /mirrordb/branches/my-branch/postmaster.pid &&
sed -i 's/^#port = 5432/port = 5501/' /mirrordb/branches/my-branch/postgresql.conf &&
su - postgres -c \"/usr/lib/postgresql/16/bin/pg_ctl start -D /mirrordb/branches/my-branch -o '-p 5501' -l /mirrordb/branches/my-branch/logfile\"
"
sleep 2
# Branch has all the data
docker exec mirrordb-engine su - postgres -c "psql -p 5501 -c 'SELECT * FROM users;'"
# Modify branch — source stays safe
docker exec mirrordb-engine su - postgres -c "psql -p 5501 -c \"INSERT INTO users (name, email) VALUES ('BranchOnly', 'new@test.com');\""
docker exec mirrordb-engine su - postgres -c "psql -p 5501 -c 'SELECT * FROM users;'"
docker exec mirrordb-engine su - postgres -c "psql -p 5500 -c 'SELECT * FROM users;'"
# ^ Source unchanged. Full isolation.+-------------------------------------------------------------+
| mirrordb-cli User-facing CLI (clap) |
| mirrordb-server REST API + orchestration (axum) |
| mirrordb-proxy PG-aware connection router (tokio) |
|-------------------------------------------------------------|
| mirrordb-replication WAL streaming + pgoutput decoder |
| mirrordb-snapshot btrfs/ZFS snapshot strategy |
| mirrordb-branch Postgres instance lifecycle |
|-------------------------------------------------------------|
| mirrordb-core Domain types, engine manager, config |
| mirrordb-store Metadata persistence (SQLx) |
+-------------------------------------------------------------+
WAL Streaming Engine (mirrordb-replication): Connects to the source database using Postgres's logical replication protocol. Creates a publication and replication slot, performs initial data sync via pg_dump/pg_restore, then streams WAL changes in real-time. Includes a hand-rolled pgoutput binary protocol decoder that parses Relation, Insert, Update, Delete, and Truncate messages.
Snapshot Strategy (mirrordb-snapshot): Abstracts over the copy-on-write filesystem (btrfs for development, ZFS for production). Creates instant snapshots of replica data -- regardless of database size, a snapshot takes ~50ms because it only creates metadata pointers, not data copies.
Connection Proxy (mirrordb-proxy): Postgres protocol-aware TCP proxy that listens on a single port and routes connections by database name. Parses the PG StartupMessage to extract the database parameter (= branch name), looks up the branch's port, and enters bidirectional TCP relay. Handles SSL negotiation and supports auto-suspend/resume of idle branches.
Branch Manager (mirrordb-branch): Manages Postgres instances inside the engine container. Creates branches by configuring postgresql.conf for a unique port, starting pg_ctl, and creating isolated credentials. Supports stop/resume for suspend functionality.
Engine Container: A Docker container running Ubuntu + btrfs + Postgres 16. All replica and branch data lives on a btrfs filesystem inside it, enabling instant CoW snapshots. In production, this would be a Linux server with ZFS.
Traditional cloning copies every byte:
500GB database --> 500GB copy --> takes 30+ minutes
MirrorDB uses btrfs/ZFS copy-on-write:
500GB database --> pointer copy --> takes 50ms
Branch writes 10MB --> only 10MB of new storage used
Total: 500GB + 10MB, not 1TB
The branch shares all data blocks with the replica. Only blocks that the branch modifies get copied (copy-on-write). This is why 50 branches of a 100GB database use roughly 100GB of disk, not 5TB.
cargo test --workspace
running 12 tests # mirrordb-core
test branch::tests::connectable_states ... ok
test branch::tests::valid_branch_transitions ... ok
test branch::tests::invalid_branch_transitions ... ok
test connector::tests::valid_transitions ... ok
test connector::tests::invalid_transitions ... ok
test id::tests::typed_ids_are_unique ... ok
test id::tests::display_includes_prefix ... ok
test id::tests::parse_round_trip ... ok
test port::tests::allocates_lowest_free_port ... ok
test port::tests::release_makes_port_available ... ok
test port::tests::mark_allocated_reserves_port ... ok
test branch::tests::credentials_generation ... ok
test result: ok. 12 passed
running 4 tests # mirrordb-proxy
test protocol::tests::build_startup_message_roundtrip ... ok
test protocol::tests::parse_startup_params_basic ... ok
test protocol::tests::parse_startup_params_empty ... ok
test protocol::tests::build_error_response_has_correct_format ... ok
test result: ok. 4 passed
running 10 tests # mirrordb-replication
test pgoutput::tests::decode_relation_message ... ok
test pgoutput::tests::decode_insert_message ... ok
test pgoutput::tests::decode_update_without_old_tuple ... ok
test pgoutput::tests::decode_update_with_old_key_tuple ... ok
test pgoutput::tests::decode_delete_message ... ok
test pgoutput::tests::decode_truncate_message ... ok
test pgoutput::tests::decode_null_column ... ok
test pgoutput::tests::decode_begin_and_commit_tags ... ok
test pgoutput::tests::decode_empty_message_fails ... ok
test pgoutput::tests::decode_unknown_tag_is_ok ... ok
test result: ok. 10 passed
26 tests, 0 failures
- Language: Rust
- HTTP: axum
- CLI: clap
- Docker: bollard
- Database: tokio-postgres, SQLx
- Replication protocol: pgwire-replication + custom pgoutput decoder
- Filesystem: btrfs (dev) / ZFS (production)
mirrordb/
crates/
mirrordb-core/ Domain types, EngineManager, PortAllocator, config
mirrordb-store/ SQLx metadata store (connectors, replicas, branches)
mirrordb-replication/ WAL streaming, pgoutput decoder, sync engine
mirrordb-snapshot/ btrfs/ZFS snapshot strategy
mirrordb-branch/ Postgres instance lifecycle
mirrordb-proxy/ PG protocol-aware connection proxy
mirrordb-server/ REST API (axum), orchestrates everything
mirrordb-cli/ CLI binary (clap)
docker/
Dockerfile.engine Ubuntu + btrfs + Postgres 16
engine-entrypoint.sh btrfs filesystem setup
seed.sql Test data for development
docker-compose.yml Dev environment
- Rust 1.88+
- Docker Desktop
- PostgreSQL client tools (pg_dump, pg_restore, psql)
# Start the development environment
docker compose up -d
# Build
cargo build --workspace
# Run tests (26 tests)
cargo test --workspace
# Start the server
cargo run -p mirrordb-server
# In another terminal
cargo run -p mirrordb-cli -- status
cargo run -p mirrordb-cli -- connector list
cargo run -p mirrordb-cli -- branch list| Service | Port | Purpose |
|---|---|---|
| metadata-db | 5480 | MirrorDB's own metadata store |
| source-db | 5481 | Simulated user's database (wal_level=logical) |
| engine | 5500-5600 | btrfs engine (replicas + branches) |
Apache-2.0