A fast, clean CLI tool written in Go that compares two databases (PostgreSQL/MySQL) for schema-level differences.
Compares the following schema elements:
- Tables - presence/absence
- Columns - data type, nullability, default values
- Primary Keys - columns
- Foreign Keys - columns, referenced table/columns, ON DELETE/UPDATE rules
- Unique Constraints - columns
- Indexes - name, columns, uniqueness
- Check Constraints - expressions (where supported)
- π§ Migration Generation - Automatically generate SQL migration scripts from detected differences
- π― Filtering Options - Ignore specific tables, columns, or schema objects
- Ignore tables by name (comma-separated list)
- Ignore tables by regex pattern
- Ignore all indexes, foreign keys, or check constraints
- β‘ Parallel Extraction - Concurrent schema extraction for faster performance on large databases
- PostgreSQL
- MySQL
Download the latest release for your platform from the Releases page.
Linux (AMD64)
wget https://github.com/YOUR_USERNAME/dbdiff/releases/latest/download/dbdiff-linux-amd64
chmod +x dbdiff-linux-amd64
sudo mv dbdiff-linux-amd64 /usr/local/bin/dbdiffLinux (ARM64)
wget https://github.com/YOUR_USERNAME/dbdiff/releases/latest/download/dbdiff-linux-arm64
chmod +x dbdiff-linux-arm64
sudo mv dbdiff-linux-arm64 /usr/local/bin/dbdiffmacOS (Intel)
wget https://github.com/YOUR_USERNAME/dbdiff/releases/latest/download/dbdiff-darwin-amd64
chmod +x dbdiff-darwin-amd64
sudo mv dbdiff-darwin-amd64 /usr/local/bin/dbdiffmacOS (Apple Silicon)
wget https://github.com/YOUR_USERNAME/dbdiff/releases/latest/download/dbdiff-darwin-arm64
chmod +x dbdiff-darwin-arm64
sudo mv dbdiff-darwin-arm64 /usr/local/bin/dbdiffWindows (AMD64)
# Download dbdiff-windows-amd64.exe from releases
# Add to your PATH or run directlyWindows (ARM64)
# Download dbdiff-windows-arm64.exe from releases
# Add to your PATH or run directly# Clone the repository
git clone https://github.com/YOUR_USERNAME/dbdiff.git
cd dbdiff
# Install dependencies
go mod download
# Build for current platform
make build
# Or build for all platforms
make build-all
# Optional: Install globally
make installdbdiff \
--source <source-connection-string> \
--source-driver <postgres|mysql> \
--target <target-connection-string> \
--target-driver <postgres|mysql> \
[options]Required Flags:
--source <conn>- Source database connection string--source-driver <driver>- Source database driver (postgres or mysql)--target <conn>- Target database connection string--target-driver <driver>- Target database driver (postgres or mysql)
Output Options:
--json- Output as JSON (for automation/CI/CD)--migration- Generate SQL migration script
Performance Options:
--parallel- Use parallel schema extraction (faster for large databases)
Filter Options:
--ignore-tables <list>- Comma-separated list of table names to ignore--ignore-table-pattern <regex>- Regex pattern for table names to ignore--ignore-indexes- Ignore all index differences--ignore-foreign-keys- Ignore all foreign key differences--ignore-checks- Ignore all check constraint differences
dbdiff \
--source "postgres://user:pass@localhost:5432/db1?sslmode=disable" \
--source-driver postgres \
--target "postgres://user:pass@localhost:5432/db2?sslmode=disable" \
--target-driver postgresdbdiff \
--source "user:pass@tcp(localhost:3306)/db1?parseTime=true" \
--source-driver mysql \
--target "user:pass@tcp(localhost:3306)/db2?parseTime=true" \
--target-driver mysqlYou can compare schemas across different database types:
dbdiff \
--source "postgres://user:pass@localhost:5432/pgdb?sslmode=disable" \
--source-driver postgres \
--target "user:pass@tcp(localhost:3306)/mysqldb?parseTime=true" \
--target-driver mysqldbdiff \
--source "postgres://user:pass@localhost:5432/db1?sslmode=disable" \
--source-driver postgres \
--target "postgres://user:pass@localhost:5432/db2?sslmode=disable" \
--target-driver postgres \
--migration > migration.sqldbdiff \
--source "..." \
--source-driver postgres \
--target "..." \
--target-driver postgres \
--ignore-tables "temp_logs,old_data,cache_table"# Ignore all tables starting with "temp_" or "old_"
dbdiff \
--source "..." \
--source-driver postgres \
--target "..." \
--target-driver postgres \
--ignore-table-pattern "^(temp_|old_)"dbdiff \
--source "..." \
--source-driver postgres \
--target "..." \
--target-driver postgres \
--ignore-indexes \
--ignore-foreign-keysdbdiff \
--source "..." \
--source-driver postgres \
--target "..." \
--target-driver postgres \
--paralleldbdiff \
--source "..." \
--source-driver postgres \
--target "..." \
--target-driver postgres \
--json0- No differences found1- Error occurred2- Differences found
This makes it easy to use in CI/CD pipelines:
if dbdiff --source "$SOURCE" --source-driver postgres --target "$TARGET" --target-driver postgres; then
echo "Schemas match!"
else
echo "Schema drift detected!"
exit 1
fiSchema Differences Found:
================================================================================
π Tables only in SOURCE:
- old_table
π Tables only in TARGET:
+ new_table
π Table: users
--------------------------------------------------------------------------------
Columns only in TARGET:
+ email_verified
Column differences:
~ age: type: integer β bigint
~ status: nullable: false β true
Primary Key: columns: [id] β [id email]
Foreign Keys only in TARGET:
+ fk_users_roles
Indexes differences:
~ idx_email: unique: false β true
{
"tables_only_in_source": ["old_table"],
"tables_only_in_target": ["new_table"],
"table_diffs": [
{
"table_name": "users",
"columns_only_in_target": ["email_verified"],
"column_diffs": [
{
"column_name": "age",
"diff": "type: integer β bigint"
}
]
}
]
}The tool is structured with clean separation of concerns:
- Models - Schema representation (Table, Column, PrimaryKey, ForeignKey, etc.)
- Dialects - Database-specific schema extraction (PostgresDialect, MySQLDialect)
- Diff Engine - Schema comparison logic
- Output - Pretty text and JSON formatters
- CLI - Command-line interface and main orchestration
To add support for a new database:
-
Implement the
Dialectinterface:type Dialect interface { ExtractSchema(db *sql.DB) (*Schema, error) }
-
Add the dialect to
getDialect()function -
Import the appropriate database driver
To test the tool, you'll need running database instances. Here's a quick setup using Docker:
# Start two PostgreSQL instances
docker run -d --name pg1 -e POSTGRES_PASSWORD=pass -p 5432:5432 postgres:15
docker run -d --name pg2 -e POSTGRES_PASSWORD=pass -p 5433:5432 postgres:15
# Create test schemas
psql "postgres://postgres:pass@localhost:5432/postgres" -c "CREATE TABLE users (id INT PRIMARY KEY, name TEXT);"
psql "postgres://postgres:pass@localhost:5433/postgres" -c "CREATE TABLE users (id BIGINT PRIMARY KEY, name TEXT, email TEXT);"
# Run comparison
./dbdiff \
--source "postgres://postgres:pass@localhost:5432/postgres?sslmode=disable" \
--source-driver postgres \
--target "postgres://postgres:pass@localhost:5433/postgres?sslmode=disable" \
--target-driver postgres# Start two MySQL instances
docker run -d --name mysql1 -e MYSQL_ROOT_PASSWORD=pass -p 3306:3306 mysql:8
docker run -d --name mysql2 -e MYSQL_ROOT_PASSWORD=pass -p 3307:3306 mysql:8
# Create test schemas
mysql -h 127.0.0.1 -P 3306 -u root -ppass -e "CREATE DATABASE testdb; USE testdb; CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(255));"
mysql -h 127.0.0.1 -P 3307 -u root -ppass -e "CREATE DATABASE testdb; USE testdb; CREATE TABLE users (id BIGINT PRIMARY KEY, name VARCHAR(255), email VARCHAR(255));"
# Run comparison
./dbdiff \
--source "root:pass@tcp(127.0.0.1:3306)/testdb?parseTime=true" \
--source-driver mysql \
--target "root:pass@tcp(127.0.0.1:3307)/testdb?parseTime=true" \
--target-driver mysqlTo create a new release with pre-built binaries:
-
Tag the release:
git tag -a v1.0.0 -m "Release version 1.0.0" git push origin v1.0.0 -
GitHub Actions will automatically:
- Build binaries for all platforms (Linux, macOS, Windows - AMD64 & ARM64)
- Generate SHA256 checksums
- Create a GitHub release with all binaries attached
- Add installation instructions to the release notes
-
Manual local build (optional):
# Build all platform binaries locally make release VERSION=1.0.0 # Binaries will be in build/ directory ls -lh build/
- Linux: AMD64, ARM64
- macOS: AMD64 (Intel), ARM64 (Apple Silicon)
- Windows: AMD64, ARM64
make help # Show all available commands
make build # Build for current platform
make build-all # Build for all platforms
make checksums # Generate SHA256 checksums
make install # Install to /usr/local/bin
make clean # Remove build artifacts
make test # Run tests
make deps # Download dependencies
make release # Create release build (requires VERSION)dbdiff/
βββ main.go # Complete implementation (~1,300 lines)
βββ go.mod # Go module definition
βββ Makefile # Build automation
βββ .github/workflows/release.yml # Automated release workflow
βββ README.md # Documentation
MIT
Contributions welcome! This is a production-ready MVP that can be extended with:
- More database support (SQLite, SQL Server, Oracle, etc.)
- Schema migration generation
- Filtering options (ignore certain tables/columns)
- Configuration file support
- Parallel schema extraction for large databases
- Data comparison (not just schema)
- Homebrew formula for easier macOS installation
- Chocolatey package for easier Windows installation