dbdiffv0.2.1

Database schema comparison CLI

Compare schemas and generate migration SQL.

Compare two databases or check a database against a SQL schema file. Review table, column and index changes, or check for drift in CI.

Rust · MIT · Last update

Product exampledbdiff
$ dbdiff postgres://prod/app --schema schema.sql

~ orders
  + paid_at       timestamptz
  + idx_paid_at   INDEX
  - payment_date  varchar(32)

$ dbdiff … --ci
# exit 0: match · exit 1: drift

dbdiff

What you can do

Database and file inputs

Compare schemas using database connection strings or a SQL file checked into your repository.

Migration SQL for review

Read table, column and index differences, then review generated SQL and locking warnings before applying it.

Exit codes and JSON

CI mode reports drift with an exit code. JSON output lets your own tooling decide what happens next.

Database schema comparison CLI

Get started

  1. Select two sources

    Point dbdiff at the environments or the SQL schema you need to compare.

  2. Inspect the migration

    Save the output, review destructive or locking operations, and run it through your normal deployment process.

01 / Install

Install

cargo install dbdiff

02 / README

Documentation

Setup, examples and API reference.

README ↗
Read the documentation

dbdiff

Rust License CI Release

Compare database schemas across environments and generate safe migration SQL — in one command.

Project website · All projects by rekurt

$ dbdiff postgres://prod/myapp postgres://staging/myapp

~ table: orders
  + column  paid_at        timestamptz NOT NULL DEFAULT now()
  + index   idx_orders_paid_at  ON orders(paid_at)
  - column  payment_date   varchar(32)

~ table: users
  + column  deleted_at     timestamptz

Generated migration → migration_20240406_143201.sql

Why dbdiff?

Most teams discover schema drift at the worst possible moment — right before a deploy. Existing tools either support only one database, require heavy setup, or can't compare a live DB against a .sql file.

dbdiff is a single binary that works anywhere CI runs.

  • Zero dependencies — one static binary, no runtime, no Docker required
  • DSN vs DSN or DSN vs SQL file — compare any two sources
  • CI-native — non-zero exit code on drift, structured output, GitHub Actions support
  • Safe migrations — warns about locking operations before you run them
  • Multi-database — Postgres today, MySQL and SQLite on the roadmap

Install

Cargo:

cargo install dbdiff

Binary — download from Releases and put it in your $PATH:

# Linux (x86_64)
curl -sSL https://github.com/rekurt/dbdiff/releases/latest/download/dbdiff-x86_64-unknown-linux-musl.tar.gz | tar xz
sudo mv dbdiff /usr/local/bin/

# macOS (Apple Silicon)
curl -sSL https://github.com/rekurt/dbdiff/releases/latest/download/dbdiff-aarch64-apple-darwin.tar.gz | tar xz
sudo mv dbdiff /usr/local/bin/

From source:

git clone https://github.com/rekurt/dbdiff.git
cd dbdiff
cargo build --release
# Binary is at ./target/release/dbdiff

Usage

Compare two live databases

dbdiff postgres://user:pass@prod-host/myapp \
       postgres://user:pass@staging-host/myapp

Compare a live database against a schema file

dbdiff postgres://user:pass@prod-host/myapp --schema ./schema.sql

Useful during code review — verify that a migration file actually matches what's in production.

Compare MySQL databases

dbdiff mysql://user:pass@prod-host/myapp mysql://user:pass@staging-host/myapp

Compare a SQLite database against a schema file

dbdiff myapp.db --schema ./schema.sql

Save the generated migration to a file

dbdiff postgres://prod/myapp postgres://staging/myapp \
  --out migration.sql

CI mode — exit 1 if schemas differ

dbdiff postgres://prod/myapp postgres://staging/myapp --ci

Returns exit code 0 if schemas match, 1 if they differ. Use this in GitHub Actions, GitLab CI, or any pipeline.

Use a custom config file

dbdiff postgres://prod/myapp postgres://staging/myapp --config ./my-config.yml

JSON output for custom tooling

dbdiff postgres://prod/myapp postgres://staging/myapp --format json

GitHub Actions

Add schema drift detection to every PR:

# .github/workflows/schema-check.yml
name: Schema check

on: [pull_request]

jobs:
  schema-drift:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install dbdiff
        run: |
          curl -sSL https://github.com/rekurt/dbdiff/releases/latest/download/dbdiff-x86_64-unknown-linux-musl.tar.gz | tar xz
          sudo mv dbdiff /usr/local/bin/

      - name: Check for schema drift
        env:
          PROD_DSN: ${{ secrets.PROD_DSN }}
          STAGING_DSN: ${{ secrets.STAGING_DSN }}
        run: dbdiff "$PROD_DSN" "$STAGING_DSN" --ci

What dbdiff detects

Object Added Removed Modified
Tables
Columns
Column types
Indexes
Unique constraints

Locking warnings

Some ALTER operations lock the table on Postgres. dbdiff marks them explicitly:

⚠  ALTER TABLE orders ADD COLUMN paid_at timestamptz NOT NULL
   This operation will rewrite the table and acquire AccessExclusiveLock.
   Consider: ADD COLUMN ... DEFAULT NULL first, then backfill.

Configuration

Create .dbdiff.yml in your project root:

# .dbdiff.yml
ignore:
  tables:
    - _migrations
    - schema_version
  columns:
    - "*.created_at"   # ignore created_at in all tables
    - "sessions.*"     # ignore all columns in sessions table

output:
  format: pretty       # pretty | json | sql
  color: true

Supported databases

Database Status Version
PostgreSQL ✅ stable 12+
MySQL / MariaDB ✅ stable 8.0+
SQLite ✅ stable 3.x

Feature flags

Database backends are optional and can be toggled via Cargo features:

# Install with only PostgreSQL support
cargo install dbdiff --no-default-features --features postgres

# Install with PostgreSQL and SQLite only
cargo install dbdiff --no-default-features --features postgres,sqlite

All backends (postgres, mysql, sqlite) are enabled by default.


Development

git clone https://github.com/rekurt/dbdiff
cd dbdiff
cargo build

# Run tests
cargo test

# Run with local SQL files
cargo run -- tests/fixtures/schema_a.sql --schema tests/fixtures/schema_b.sql

# Run with a local Postgres
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=pass postgres:16
cargo run -- postgres://postgres:pass@localhost/myapp --schema tests/fixtures/schema_b.sql

Project layout

src/
  main.rs          CLI entry point
  lib.rs           Library root
  cli.rs           Argument parsing (clap)
  model.rs         Schema / Table / Column / Index structs
  error.rs         Error types
  diff.rs          Schema comparison engine
  migration.rs     SQL migration generator
  output.rs        Terminal rendering (colored diff)
  config/
    mod.rs         Config file parsing (.dbdiff.yml)
    filter.rs      Schema filtering (ignore tables/columns)
  loader/
    mod.rs         Source dispatch logic
    postgres.rs    PostgreSQL introspection
    mysql.rs       MySQL / MariaDB introspection
    sqlite.rs      SQLite introspection
    sqlfile.rs     .sql file parser
tests/
  cli.rs           Integration tests
  config.rs        Config integration tests
  fixtures/        SQL test schemas + config fixtures

Contributing

Issues and PRs are welcome. Please open an issue before working on a large change.

For a new database driver, see src/loader/postgres.rs — implement a load function returning Schema and add detection logic in src/loader/mod.rs.

See CONTRIBUTING.md for full details.


License

MIT © Nikita

dbdiff

Compare your database schemas

Install dbdiff →

03 / All projects

More projects by rekurt

Libraries, command-line tools and applications.

All projects