dbdiff / dbdiff
Requires
- php: >=7.3
- ext-json: *
- aura/cli: 2.*@dev
- diff/diff: ~3.0
- illuminate/container: ^8|^9|^10|^11
- illuminate/database: ^8|^9|^10|^11
- illuminate/view: ^8|^9|^10|^11
- symfony/yaml: ^5.1|^6.0|^7.0
Requires (Dev)
- ext-pdo: *
- phpunit/phpunit: ^9.4.3|^10.0|^11.0
- dev-master
- v2.0.0
- v1.0.0
- dev-feature/win-fix-release-6
- dev-feature/win-fix-release-5
- dev-feature/fix-win-release-4
- dev-feature/fix-win-release-3
- dev-feature/fix-win-release-2
- dev-fix/windows-binaries
- dev-feature/fix-releases
- dev-copilot/fix-binary-failures-and-npm-step
- dev-feature/dbdiff-multi-platform-binaries
- dev-feature/expanded-migrations
- dev-feature/sqlite-postgres-support
- dev-feature/gh-scripts
- dev-feature/support-php-85-mysql-96
- dev-pr/108
- dev-better-ci-coverage
This package is auto-updated.
Last update: 2026-03-08 14:13:22 UTC
README
DBDiff is an automated database schema and data diff tool. It compares two databases, local or remote, and produces a migration file of the differences automatically.
When used alongside a compatible database migration tool, it can help enable database version control within your team or enterprise.
Features
- Compares two databases (local or remote) and generates SQL migrations automatically
- Diffs schema changes, data changes, or both — with deterministic, predictable output
- Up and down SQL generated in the same file
- Supports MySQL, PostgreSQL, and SQLite via
--driver - Supabase-ready via
--supabaseone-flag shorthand - Works with Flyway, Liquibase, Laravel Migrations, and more
- Ignore specific tables or fields via a YAML config file
- Unicode / UTF-8 aware
- Fast — tested on databases with millions of rows
- Runs on Windows, Linux and macOS (command-line / Terminal)
Supported Databases
Other versions may work but are not actively tested. PRs to add official support are welcome.
MySQL
| Version | Status |
|---|---|
| MySQL 8.0.x | ✅ Supported |
| MySQL 8.4.x (LTS) | ✅ Supported |
| MySQL 9.3.x (Innovation) | ✅ Supported |
| MySQL 9.6.x (Innovation) | ✅ Supported |
PostgreSQL
Use --driver=pgsql (or driver: pgsql in your .dbdiff config).
| Version | Status |
|---|---|
| PostgreSQL 14.x | ✅ Supported |
| PostgreSQL 15.x | ✅ Supported |
| PostgreSQL 16.x (LTS) | ✅ Supported |
| PostgreSQL 17.x | ✅ Supported |
| PostgreSQL 18.x | ✅ Supported |
SQLite
Use --driver=sqlite. The file path is passed as the database name:
./dbdiff --driver=sqlite server1./path/to/source.db:server1./path/to/target.db
SQLite 3.x is supported (any version supported by the installed pdo_sqlite PHP extension).
Supabase
--supabase sets driver=pgsql and enables SSL automatically:
./dbdiff --supabase --server1=user:pass@db.xxx.supabase.co:5432 server1.mydb:server1.mydb
Compatible Database Variants
The databases below work with DBDiff's existing drivers with no code changes. Unless otherwise noted, these have not been tested by the core team. PRs to add official support are welcome.
MySQL-compatible — --driver=mysql (default)
| Database | Notes |
|---|---|
| MariaDB 10.x / 11.x | MySQL wire protocol; minor DDL dialect differences |
| AWS Aurora MySQL | Standard MySQL protocol |
| PlanetScale | MySQL-compatible SaaS |
| Vitess / VTGate | MySQL wire protocol via VTGate |
| Percona XtraDB Cluster | MySQL-compatible; Galera replication metadata ignored |
| TiDB | MySQL-compatible; default port 4000 |
PostgreSQL-compatible — --driver=pgsql
| Database | Notes |
|---|---|
| AWS Aurora PostgreSQL | Standard pgsql connection |
| AWS RDS PostgreSQL | Standard pgsql connection |
| Neon | Standard pgsql; supports branch diffing (see below) |
| AlloyDB (Google Cloud) | Google's Postgres-compatible offering |
| CockroachDB | Postgres wire protocol; some DDL differences |
| YugabyteDB | Postgres-compatible YSQL layer |
| Multigres | Transparent Postgres proxy; no changes needed |
| TimescaleDB | Postgres extension; hypertable DDL diffs natively |
| pgvector | vector(N) columns and HNSW/IVFFlat indexes diff natively |
Neon Branching
Neon's copy-on-write branching lets you diff any two branches directly:
./dbdiff \ --server1-url postgres://user:pass@main-branch.hostname.neon.tech/mydb \ --server2-url postgres://user:pass@feature-branch.hostname.neon.tech/mydb \ --format=flyway --description=my_feature
Dolt (Git for Databases)
Dolt is a MySQL-compatible database with Git-style branching. Each branch is exposed as a separate database:
./dbdiff server1.main:server1.feature_add_users
Installation
The quickest way to get started is to download a pre-built release directly from GitHub Releases — no PHP, Node, or Composer required:
| Method | Available on Releases? | Best for |
|---|---|---|
| Pre-built binary | ✅ Yes | Quickest start — zero dependencies |
| PHAR | ✅ Yes | Single portable file; requires PHP ≥ 8.1 |
| npm | ✅ Yes (via registry) | Node.js projects or CI pipelines |
| Docker | — | Isolated environments or testing |
| Composer (source) | — | Contributing to DBDiff or PHP integration |
PHP requirement: Pre-built binaries, npm packages, and Docker images bundle PHP 8.3 — no system PHP needed. The PHAR and Composer installs require PHP ≥ 8.1 on your system.
Pre-built Binaries
Download from GitHub Releases. No PHP, Node, or Composer required.
| Platform | Asset |
|---|---|
| Linux x64 (glibc) | dbdiff-linux-x64 |
| Linux x64 (Alpine / musl) | dbdiff-linux-x64-musl |
| Linux arm64 (glibc) | dbdiff-linux-arm64 |
| Linux arm64 (Alpine / musl) | dbdiff-linux-arm64-musl |
| macOS Apple Silicon | dbdiff-darwin-arm64 |
| macOS Intel | dbdiff-darwin-x64 |
| Windows x64 | dbdiff-win32-x64.exe |
| Windows arm64 | dbdiff-win32-arm64.exe |
After downloading, make it executable (Linux/macOS) and optionally move it to your PATH:
chmod +x dbdiff-linux-x64 sudo mv dbdiff-linux-x64 /usr/local/bin/dbdiff dbdiff --version
npm
npm install -g @dbdiff/cli dbdiff --version
The correct platform binary is selected automatically at install time. Supported: Linux x64/arm64 (glibc + musl), macOS x64/arm64, Windows x64/arm64.
PHAR
Download dbdiff.phar from GitHub Releases. Requires PHP ≥ 8.1.
chmod +x dbdiff.phar sudo mv dbdiff.phar /usr/local/bin/dbdiff dbdiff --version
To build a PHAR locally from source, see Building a PHAR.
Docker
Pre-built multi-arch images (linux/amd64 + linux/arm64) are published to GHCR on every release.
Pull and run (no build required)
docker pull ghcr.io/dbdiff/dbdiff docker run --rm ghcr.io/dbdiff/dbdiff --version docker run --rm ghcr.io/dbdiff/dbdiff --driver=mysql \ --server1=user:pass@host:3306 server1.mydb:server1.mydb
Image variants
| Tag pattern | Registry | Description |
|---|---|---|
latest, {version}, slim-{version} |
GHCR | Slim — PHAR + PHP Alpine (~120 MB). For production use / CI. |
full, full-{version} |
GHCR | Full — Composer source install (~600 MB). For development and cross-version testing. |
Build locally
# Slim image (requires dist/dbdiff.phar — run `vendor/bin/box compile` first) docker build -f docker/Dockerfile.slim -t dbdiff:slim . docker run --rm dbdiff:slim --version # Full image (Composer install from source — no PHAR needed) docker build -f docker/Dockerfile -t dbdiff:full .
See DOCKER.md for cross-version testing, Podman usage, and start.sh flags.
Composer Source Install
git clone https://github.com/DBDiff/DBDiff.git
cd DBDiff
composer install --optimize-autoloader
Or as a project dependency:
composer require "dbdiff/dbdiff:@dev"
Or globally:
composer global require "dbdiff/dbdiff:@dev"
After installing from source, continue with Setup.
Setup
For source installs (git clone / Composer) only. Binaries, PHAR, npm, and Docker do not require these steps.
- Create a
.dbdiffconfig file — see File Examples - Run:
./dbdiff server1.db1:server1.db2
Expected output:
ℹ Now calculating schema diff for table `foo`
ℹ Now generating UP migration
ℹ Writing migration file to /path/to/dbdiff/migration.sql
✔ Completed
Command-Line API
Flags always override settings in .dbdiff.
| Flag | Description |
|---|---|
--server1=user:pass@host:port |
Source connection. Omit if using only one server. |
--server2=user:pass@host:port |
Target connection (if different from server1). |
--driver=mysql|pgsql|sqlite |
Database driver. Defaults to mysql. |
--supabase |
Shorthand for --driver=pgsql + SSL. |
--format=native|flyway|liquibase-xml|liquibase-yaml|laravel |
Output format. Defaults to native. |
--description=<slug> |
Slug used in generated filenames. |
--template=<path> |
Custom output template. |
--type=schema|data|all |
What to diff. Defaults to schema. |
--include=up|down|all |
Directions to include. Defaults to up. |
--nocomments=true |
Strip comment headers from output. |
--config=<file> |
Config file path. Defaults to .dbdiff. |
--output=<path> |
Output file path. Defaults to migration.sql. |
server1.db1:server2.db2 |
Databases to compare. Or a single table: server1.db1.table1:server2.db2.table1. |
Usage Examples
MySQL (default)
./dbdiff server1.db1:server2.db2
MySQL — data diff only
./dbdiff server1.dev.table1:server2.prod.table1 --nocomments=true --type=data
MySQL — Flyway format with output path
./dbdiff --format=flyway --description=add_users --include=all \ server1.db1:server2.db2 --output=./sql/
PostgreSQL
./dbdiff --driver=pgsql --server1=user:pass@localhost:5432 server1.staging:server1.production
Supabase
./dbdiff --supabase --server1=postgres:pass@db.xxxx.supabase.co:5432 \ server1.staging:server1.production
SQLite
./dbdiff --driver=sqlite server1./var/db/v1.db:server1./var/db/v2.db
File Examples
A single dbdiff.yml file in your project root configures both the diff command and the migration runner. Copy dbdiff.yml.example to get started.
Auto-detected filenames, in priority order:
| Filename | Notes |
|---|---|
.dbdiff |
Legacy — still supported for backwards compatibility |
dbdiff.yml |
Recommended — YAML syntax highlighting, single file for everything |
.dbdiff.yml |
Hidden-file variant |
dbdiff.yaml |
.yaml extension variant |
You can also pass any filename explicitly: ./dbdiff --config=myconfig.yml server1.db:server2.db
dbdiff.yml
# ── Diff command (./dbdiff server1.db:server2.db) ───────────────────────── server1: user: user password: password port: 3306 # MySQL: 3306 | PostgreSQL: 5432 host: localhost server2: user: user password: password port: 3306 host: host2 driver: mysql # mysql | pgsql | sqlite type: all include: all nocomments: true tablesToIgnore: - table1 - table2 fieldsToIgnore: table1: - field1 - field2 # ── Migration runner (dbdiff migrate:up) ────────────────────────────────── database: driver: mysql host: localhost port: 3306 name: mydb user: root password: secret migrations: dir: ./migrations history_table: _dbdiff_migrations
How Does the Diff Work?
Comparisons run in this order:
Overall
- Checks both databases exist and are accessible
- Compares database collation between source and target
Schema
- Detects differences in column count, name, type, collation or attributes
- New columns in the source are added to the target
Data
- Compares table storage engine, collation, and row count
- Records changed rows and missing rows per table
Compatible Migration Tools
DBDiff supports multiple output formats via --format. Use --description=<slug> to customise generated filenames.
--format |
Tool | Language | Output | Notes |
|---|---|---|---|---|
native (default) |
Plain SQL | Any | migration.sql |
Up, down, or both |
flyway |
Flyway | Java | V{ts}__{desc}.sql |
Down adds U{ts}__{desc}.sql (Flyway Teams) |
liquibase-xml |
Liquibase | Java | changelog.xml |
Both directions in one file |
liquibase-yaml |
Liquibase | Java | changelog.yaml |
Both directions in one file |
laravel |
Laravel Migrations | PHP | YYYY_MM_DD_HHMMSS_{desc}.php |
up()/down() methods |
| (template) | Simple DB Migrate | Python | custom | Use --template=templates/simple-db-migrate.tmpl |
Let us know if you're using DBDiff with other tools so we can add them here.
Building a PHAR
PHARs are built automatically and attached to every GitHub Release. To build locally from source:
composer install vendor/bin/box compile
Output: dist/dbdiff.phar — rename and move to /usr/local/bin/dbdiff if desired.
box.jsonis pre-configured with GZ compression andcheck-requirements: falseso the PHAR works correctly when stitched with the static micro SAPI runtime used in the pre-built binaries.
Releasing 🚀
Automated (recommended)
- Go to GitHub Actions → Release DBDiff → Run workflow
- Enter the version number (e.g.
2.1.0— novprefix) - The workflow will:
- Build the PHAR with Box
- Build self-contained binaries for all 8 platforms via static-php-cli
- Publish all
@dbdiff/cli-*packages to npm (skips any already published) - Create or update the GitHub Release with all assets
- Create the git tag (skipped if it already exists)
Manual / local
# Build PHAR + tag scripts/release.sh v2.1.0 git push origin v2.1.0 # Build Linux binaries locally (requires Podman or Docker) SKIP_PHAR=1 scripts/release-binaries.sh 2.1.0 # Upload assets to an existing GitHub Release gh release upload v2.1.0 --clobber \ dist/dbdiff.phar \ packages/@dbdiff/cli-linux-x64/dbdiff \ packages/@dbdiff/cli-linux-x64-musl/dbdiff \ packages/@dbdiff/cli-linux-arm64/dbdiff \ packages/@dbdiff/cli-linux-arm64-musl/dbdiff # Update the Homebrew tap formula scripts/update-homebrew-formula.sh 2.1.0 ../homebrew-dbdiff
Cross-Version Testing
Test DBDiff locally against any combination of PHP and MySQL:
# Single combination ./start.sh 8.3 8.0 # All 16 combinations in parallel ./start.sh all all --parallel
The CI matrix: 6 PHP × 4 MySQL = 24 jobs, plus dedicated jobs for SQLite and PostgreSQL.
See DOCKER.md for flags covering fast restarts, recording fixtures, and CI usage.
Questions & Support 💡
- Open a new issue or check existing ones
- For commercial support enquiries, get in touch
Contributions 💖
Please read the Contributing Guide before submitting a PR.
Feedback 💬
Could you spare 2 minutes to share your feedback?
https://forms.gle/gjdJxZxdVsz7BRxg7