PHPackages                             dbdiff/dbdiff - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. dbdiff/dbdiff

ActiveProject[Database &amp; ORM](/categories/database)

dbdiff/dbdiff
=============

v2.0.0(4mo ago)740119.5k↑91.1%159[4 issues](https://github.com/DBDiff/DBDiff/issues)[2 PRs](https://github.com/DBDiff/DBDiff/pulls)MITPHPPHP &gt;=7.3CI passing

Since Apr 6Pushed 1w ago35 watchersCompare

[ Source](https://github.com/DBDiff/DBDiff)[ Packagist](https://packagist.org/packages/dbdiff/dbdiff)[ RSS](/packages/dbdiff-dbdiff/feed)WikiDiscussions master Synced yesterday

READMEChangelog (4)Dependencies (7)Versions (39)Used By (0)

[![DBDiff logo](https://avatars3.githubusercontent.com/u/12562465?s=200&v=4)](https://dbdiff.github.io/DBDiff/)

 [![Build Status](https://github.com/DBDiff/DBDiff/actions/workflows/tests.yml/badge.svg)](https://github.com/DBDiff/DBDiff/actions/workflows/tests.yml) [![Total Downloads](https://camo.githubusercontent.com/44de1558412511677f7046ccce0697c1ab0d0c67f66479de04db57cb6b2dee45/68747470733a2f2f706f7365722e707567782e6f72672f6462646966662f6462646966662f646f776e6c6f616473)](https://packagist.org/packages/dbdiff/dbdiff) [![Monthly Downloads](https://camo.githubusercontent.com/45a338856206d971bb110172d2dc731787a04da99a7d3a4c407488bbb7ccff46/68747470733a2f2f706f7365722e707567782e6f72672f6462646966662f6462646966662f642f6d6f6e74686c79)](https://packagist.org/packages/dbdiff/dbdiff) [![](https://camo.githubusercontent.com/fd662b08e30002a39a03dfff5c3ac8b95b2d9a43f80b2f013592cb6b45ecb643/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f636f6e7472696275746f72732f6462646966662f6462646966662e737667)](https://github.com/dbdiff/dbdiff/graphs/contributors) [![License](https://camo.githubusercontent.com/431277db80dec69bc9f5fbe3dbb39401d051a05ba30202e2088829f8bc6ccae4/68747470733a2f2f706f7365722e707567782e6f72672f6462646966662f6462646966662f6c6963656e7365)](https://packagist.org/packages/dbdiff/dbdiff)

 **DBDiff** is an automated database schema and data diff tool for MySQL, Postgres &amp; SQLite. It compares two databases, local or remote, and produces a migration file of the differences automatically.

 When used alongside a [compatible database migration tool](#compatible-migration-tools), it can help enable database version control within your team or enterprise.

Features
--------

[](#features)

- Compares two databases (local or remote) and generates SQL migrations automatically
- Supports MySQL, PostgreSQL, and SQLite via `--driver`
- Connect via DSN URLs (`--server1-url`, `--server2-url`, `--db-url`) — works with any connection string
- [Supabase](https://supabase.com)-ready via `--supabase` one-flag shorthand (not required when using DSN URLs)
- Diffs tables, views, triggers, stored procedures/functions, enum types, and data — with deterministic, predictable output
- Up and down SQL generated in the same file
- Built-in migration runner: `migration:up`, `down`, `status`, `validate`, `repair`, `baseline`
- Works with [Flyway, Liquibase, Laravel Migrations, and more](#compatible-migration-tools)
- 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
-------------------

[](#supported-databases)

*Other versions may work but are not actively tested. PRs to add official support are welcome.*

### MySQL

[](#mysql)

VersionStatusMySQL 8.0.x✅ SupportedMySQL 8.4.x (LTS)✅ SupportedMySQL 9.3.x (Innovation)✅ SupportedMySQL 9.6.x (Innovation)✅ Supported### PostgreSQL

[](#postgresql)

Use `--driver=pgsql` (or `driver: pgsql` in your `.dbdiff` config).

VersionStatusPostgreSQL 14.x✅ SupportedPostgreSQL 15.x✅ SupportedPostgreSQL 16.x (LTS)✅ SupportedPostgreSQL 17.x✅ SupportedPostgreSQL 18.x✅ Supported### SQLite

[](#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)

`--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
----------------------------

[](#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)

[](#mysql-compatible----drivermysql-default)

DatabaseNotesMariaDB 10.x / 11.xMySQL wire protocol; minor DDL dialect differencesAWS Aurora MySQLStandard MySQL protocolPlanetScaleMySQL-compatible SaaSVitess / VTGateMySQL wire protocol via VTGatePercona XtraDB ClusterMySQL-compatible; Galera replication metadata ignoredTiDBMySQL-compatible; default port 4000[Dolt](https://github.com/dolthub/dolt)MySQL-compatible, version-controlled; **CI-tested**### PostgreSQL-compatible — `--driver=pgsql`

[](#postgresql-compatible----driverpgsql)

DatabaseNotesAWS Aurora PostgreSQLStandard pgsql connectionAWS RDS PostgreSQLStandard pgsql connection[Neon](https://neon.tech)Standard pgsql; supports branch diffing (see below)AlloyDB (Google Cloud)Google's Postgres-compatible offeringCockroachDBPostgres wire protocol; some DDL differencesYugabyteDBPostgres-compatible YSQL layerMultigresTransparent Postgres proxy; no changes neededTimescaleDBPostgres extension; hypertable DDL diffs nativelypgvector`vector(N)` columns and HNSW/IVFFlat indexes diff natively### Neon Branching

[](#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-git-for-databases)

[Dolt](https://github.com/dolthub/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
------------

[](#installation)

The quickest way to get started is to download a pre-built release directly from [**GitHub Releases**](https://github.com/DBDiff/DBDiff/releases/latest) — no PHP, Node, or Composer required:

MethodAvailable on Releases?Best for[Pre-built binary](#pre-built-binaries)✅ YesQuickest start — zero dependencies[PHAR](#phar)✅ YesSingle portable file; requires PHP ≥ 8.1[npm](#npm)✅ Yes (via registry)Node.js projects or CI pipelines[Docker / Podman](#docker--podman)—Isolated environments, CI, or no local PHP[Composer (source)](#composer-source-install)—Contributing to DBDiff or PHP integration> **PHP requirement:** Pre-built binaries, npm packages, and Docker/Podman images bundle PHP 8.3 — no system PHP needed. The PHAR and Composer installs require **PHP ≥ 8.1** on your system.

Pre-built Binaries
------------------

[](#pre-built-binaries)

Download from [**GitHub Releases**](https://github.com/DBDiff/DBDiff/releases/latest). No PHP, Node, or Composer required.

PlatformAssetLinux 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)

```
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.

Packages are also published to **GitHub Packages** as a mirror. If npmjs.org is unavailable:

```
npm install -g @dbdiff/cli --registry=https://npm.pkg.github.com
```

PHAR
----

[](#phar)

Download `dbdiff.phar` from [**GitHub Releases**](https://github.com/DBDiff/DBDiff/releases/latest). 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](#building-a-phar).

Docker / Podman
---------------

[](#docker--podman)

Pre-built multi-arch images (linux/amd64 + linux/arm64) are published to GHCR on every release. Both Docker and [Podman](https://podman.io/) are fully supported — use whichever is available on your system. No local PHP installation is required.

### Pull and run (no build required)

[](#pull-and-run-no-build-required)

**Docker:**

```
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
```

**Podman** (drop-in replacement — commands are identical):

```
podman pull ghcr.io/dbdiff/dbdiff
podman run --rm ghcr.io/dbdiff/dbdiff --version
podman run --rm ghcr.io/dbdiff/dbdiff --driver=mysql \
  --server1=user:pass@host:3306 server1.mydb:server1.mydb
```

> **Podman on Linux** runs rootless by default — no daemon required. Install via your package manager: `sudo apt install podman` (Debian/Ubuntu) or `brew install podman` (macOS).

### Image variants

[](#image-variants)

Tag patternRegistryDescription`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

[](#build-locally)

```
# Slim image (requires dist/dbdiff.phar — run `vendor/bin/box compile` first)
# Replace 'docker' with 'podman' if using Podman
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](DOCKER.md) for cross-version testing, Podman setup, and start.sh flags.

Composer Source Install
-----------------------

[](#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).

Setup
-----

[](#setup)

*For source installs (git clone / Composer) only. Binaries, PHAR, npm, and Docker do not require these steps.*

1. Create a `.dbdiff` config file — see [File Examples](#file-examples)
2. 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
----------------

[](#command-line-api)

### `diff` (default command)

[](#diff-default-command)

*Flags always override settings in `.dbdiff`.*

FlagDescription`--server1=user:pass@host:port`Source connection. Omit if using only one server.`--server2=user:pass@host:port`Target connection (if different from server1).`--server1-url=`Full DSN URL for source (e.g. `postgres://user:pass@host:5432/db`).`--server2-url=`Full DSN URL for target. Supported schemes: `mysql://`, `pgsql://`, `postgres://`, `postgresql://`, `sqlite://`.`--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 used in generated filenames.`--template=`Custom output template.`--type=schema|data|all`What to diff. Defaults to `schema`.`--include=up|down|both`Directions to include. Defaults to `up`. (`all` is accepted as an alias for `both`.)`--nocomments`Strip comment headers from output.`--config=`Config file path. Defaults to `.dbdiff`.`--output=`Output file path. Defaults to `migration.sql`.`--memory-limit=`PHP memory limit for this run (e.g. `512M`, `1G`, `2G`, `-1` for unlimited). Overrides the 1G default and any `memory_limit` setting in your config file.`--tables=`Comma-separated table include list (supports globs: `*`, `?`). Only these tables are diffed. Example: `--tables=users,orders,wp_*``--ignore-tables=`Comma-separated table exclude list (supports globs: `*`, `?`). Example: `--ignore-tables=cache_*,temp_*``--debug`Enable verbose error output.`server1.db1:server2.db2`Databases to compare. Or a single table: `server1.db1.table1:server2.db2.table1`.> **UP only by default:** The generated file includes only the UP (forward) migration by default. To also generate the DOWN (rollback) section, pass `--include=all`. Example: `dbdiff diff --include=all ...`

> **DSN URLs vs `--server` flags:** Use `--server1-url` / `--server2-url` when you have a connection string (common with Supabase, Neon, Railway, etc.). Use `--server1` / `--server2` when specifying credentials separately.

> **Passwords with special characters:** Embed the password percent-encoded in the URL. Use `dbdiff url:encode` to safely encode any password (see [`url:encode`](#urlencode--password-encoder) below). If dbdiff is not yet installed, `scripts/encode-password.sh` works without any dependencies.

> **Memory:** The CLI sets a default PHP memory limit of 1G. Diffing very large databases may need more — pass `--memory-limit=2G` on the command line or add `memory_limit: 2G` to your `.dbdiff` / `dbdiff.yml` config. The CLI flag always wins over the config file.

### `url:encode` — Password encoder

[](#urlencode--password-encoder)

Percent-encodes a raw password for safe embedding in any `--server-url` connection string.

```
dbdiff url:encode ''
```

Capture the result directly into a connection flag:

```
PASS=$(dbdiff url:encode 'my$ecret#pass@word%123')
dbdiff diff \
  --server1-url="postgres://user:${PASS}@db.xxxx.supabase.co:5432/postgres" \
  --server2-url="postgres://user:pass@db.yyyy.supabase.co:5432/postgres"
```

Accepts stdin too, for use in pipelines:

```
echo 'my$ecret#pass' | dbdiff url:encode
```

All characters except RFC 3986 unreserved characters (`A–Z a–z 0–9 - _ . ~`) are encoded. This is the safe, zero-guesswork approach for any password — including ones containing `@`, `#`, `?`, `/`, `+`, and literal `%`.

**If dbdiff is not yet installed** (e.g. you are setting up CI), use the included bash script instead — no Python, Node, or PHP required:

```
PASS=$(scripts/encode-password.sh 'my$ecret#pass@word%123')
```

### Migration Runner

[](#migration-runner)

DBDiff includes a built-in migration runner. All `migration:*` commands accept:

FlagDescription`--db-url=`Full DSN URL for the target database.`--migrations-dir=`Override the migrations directory.`--config=`Path to `dbdiff.yml`.CommandDescriptionExtra flags`migration:new `Scaffold a new migration file.`--format=supabase` — plain `.sql` (no DOWN); auto-set inside Supabase projects`migration:up`Apply all pending migrations.`--target=` — stop after this version`migration:down`Roll back applied migration(s).`--last=` (default `1`), `--target=``migration:status`Show applied vs pending migrations. Adds a **Supa?** column inside Supabase projects.—`migration:validate`Verify on-disk checksums match the history table.—`migration:repair`Remove failed entries so they can be retried.`--force` — skip confirmation`migration:baseline`Mark current DB state as the migration baseline.`--baseline-version=`, `--description=`, `--force`#### Migration file formats

[](#migration-file-formats)

DBDiff supports two on-disk formats in the same directory:

FormatFile patternBest for**Native** (default)`{version}_{name}.up.sql` + optional `.down.sql`New projects, rollback support**Supabase**`{version}_{name}.sql` (UP only)Existing `supabase/migrations/` directoriesIf both formats exist for the same version timestamp, the native `.up.sql` file takes precedence.

#### Supabase project auto-detection

[](#supabase-project-auto-detection)

When DBDiff is run inside (or below) a directory that contains `supabase/config.toml`, it automatically:

- Sets the migrations directory to `supabase/migrations/` (no `--migrations-dir` needed)
- Defaults `migration:new` to Supabase format — creating a plain `.sql` file
- Shows a **Supa?** column in `migration:status`, indicating which migrations Supabase's own `schema_migrations` table considers applied

Pass `--format=native` to `migration:new` to override the auto-detected format.

Usage Examples
--------------

[](#usage-examples)

### MySQL (default)

[](#mysql-default)

```
./dbdiff server1.db1:server2.db2
```

### MySQL — data diff only

[](#mysql--data-diff-only)

```
./dbdiff server1.dev.table1:server2.prod.table1 --nocomments --type=data
```

### MySQL — Flyway format with output path

[](#mysql--flyway-format-with-output-path)

```
./dbdiff --format=flyway --description=add_users --include=all \
  server1.db1:server2.db2 --output=./sql/
```

### PostgreSQL

[](#postgresql-1)

```
./dbdiff --driver=pgsql --server1=user:pass@localhost:5432 server1.staging:server1.production
```

### Supabase

[](#supabase-1)

```
./dbdiff --supabase --server1=postgres:pass@db.xxxx.supabase.co:5432 \
  server1.staging:server1.production
```

### SQLite

[](#sqlite-1)

```
./dbdiff --driver=sqlite server1./var/db/v1.db:server1./var/db/v2.db
```

### DSN URLs

[](#dsn-urls)

```
./dbdiff diff \
  --server1-url='postgres://user:pass@db.xxxx.supabase.co:5432/postgres' \
  --server2-url='postgres://user:pass@db.yyyy.supabase.co:5432/postgres'
```

If your password contains special characters, use `dbdiff url:encode` (see [`url:encode`](#urlencode--password-encoder) in the Command-Line API section):

```
PASS=$(dbdiff url:encode 'my$ecret#pass@word%123')
./dbdiff diff \
  --server1-url="postgres://user:${PASS}@db.xxxx.supabase.co:5432/postgres" \
  --server2-url='postgres://user:pass@db.yyyy.supabase.co:5432/postgres'
```

### Migration runner

[](#migration-runner-1)

```
# Scaffold a new migration (DBDiff native format)
./dbdiff migration:new create_users_table

# Scaffold a Supabase-format migration (plain .sql, no DOWN file)
./dbdiff migration:new create_users_table --format=supabase

# Inside a Supabase project, format and directory are auto-detected:
cd my-supabase-project   # contains supabase/config.toml
./dbdiff migration:new create_users_table   # → supabase/migrations/{ts}_create_users_table.sql

# Apply all pending migrations
./dbdiff migration:up --db-url='postgres://user:pass@localhost:5432/mydb'

# Check status (adds a Supa? column inside Supabase projects)
./dbdiff migration:status --db-url='postgres://user:pass@localhost:5432/mydb'

# Roll back the last migration
./dbdiff migration:down --db-url='postgres://user:pass@localhost:5432/mydb'

# Validate checksums
./dbdiff migration:validate --db-url='postgres://user:pass@localhost:5432/mydb'
```

### Supabase — diff with local stack auto-fill

[](#supabase--diff-with-local-stack-auto-fill)

When inside a Supabase project (`supabase/config.toml` present) and the local stack is running (`supabase start`), `--server1-url` is resolved automatically from `supabase status`:

```
# Only supply the remote (production) URL — local stack fills in automatically
./dbdiff diff --server2-url='postgres://user:pass@db.yyyy.supabase.co:5432/postgres'
```

File Examples
-------------

[](#file-examples)

A single `dbdiff.yml` file in your project root configures both the diff command and the migration runner. Copy [`dbdiff.yml.example`](dbdiff.yml.example) to get started.

Auto-detected filenames, in priority order:

FilenameNotes`.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 variantYou can also pass any filename explicitly: `./dbdiff --config=myconfig.yml server1.db:server2.db`

### `dbdiff.yml`

[](#dbdiffyml)

```
# ── 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

# ── Filtering ─────────────────────────────────────────────────────────────
# Include list — only these tables are diffed (supports globs: *, ?).
# When set, only matching tables are included. Omit to diff all tables.
# tables:
#   - users
#   - orders
#   - wp_*

# Exclude list — skip these tables entirely (supports globs).
tablesToIgnore:
  - table1
  - table2

# Exclude from data diff only — schema is still diffed (supports globs).
# tablesDataToIgnore:
#   - audit_log
#   - event_stream

# Per-table column exclusion (keys support globs: *, ?).
fieldsToIgnore:
  table1:
    - field1
    - field2

# Per-table row filtering — skip rows matching a column-value regex.
# rowsToIgnore:
#   wp_options:
#     - { column: option_name, pattern: "_transient_.*" }
#     - { column: option_name, pattern: "_site_transient_.*" }
#   sessions:
#     - { column: status, pattern: "expired|archived" }

# Per-table scope override: schema, data, or all (default).
# tableScope:
#   audit_log: schema
#   config: data

# ── Migration runner (dbdiff migration:up) ────────────────────────────────
database:
  driver: mysql
  host: localhost
  port: 3306
  name: mydb
  user: root
  password: secret

migrations:
  dir: ./migrations
  history_table: _dbdiff_migrations
```

Filtering
---------

[](#filtering)

DBDiff offers fine-grained control over what enters the diff. All list values support **glob patterns** (`*` matches any characters, `?` matches a single character).

DimensionConfig keyCLI flagScopeTable include list`tables``--tables`schema + dataTable exclude list`tablesToIgnore``--ignore-tables`schema + dataData-only exclude`tablesDataToIgnore`—data onlyColumn exclusion`fieldsToIgnore`—schema + dataRow filtering`rowsToIgnore`—data onlyPer-table scope`tableScope`—override**Priority**: include list is applied first (only matching tables pass), then the exclude list narrows further. `tablesDataToIgnore` removes tables from data comparison only. `tableScope` can override a table to `schema`, `data`, or `all`.

**Glob examples**: `wp_*` matches all WordPress tables, `*_backup` matches any table ending in `_backup`, `log_?` matches `log_a` through `log_z`.

```
# Only diff tables matching these patterns
tables:
  - users
  - orders
  - wp_*

# Skip these tables entirely
tablesToIgnore:
  - cache_*
  - _dbdiff_migrations

# Skip data diff for these (schema is still compared)
tablesDataToIgnore:
  - audit_log

# Exclude columns per table (keys support globs)
fieldsToIgnore:
  users:
    - updated_at
    - last_login
  wp_*:
    - ID

# Skip rows matching column-value regex
rowsToIgnore:
  wp_options:
    - { column: option_name, pattern: "_transient_.*" }
  sessions:
    - { column: status, pattern: "expired|archived" }

# Override scope per table: schema | data | all
tableScope:
  audit_log: schema
  config: data
```

How Does the Diff Work?
-----------------------

[](#how-does-the-diff-work)

Comparisons run in this order:

### Overall

[](#overall)

- Checks both databases exist and are accessible
- Compares database collation between source and target

### Schema

[](#schema)

- Detects differences in column count, name, type, collation or attributes
- New columns in the source are added to the target

### Views

[](#views)

- Detects created, dropped, and altered views across source and target
- ALTER = DROP IF EXISTS + CREATE with the new definition

### Triggers

[](#triggers)

- Detects created, dropped, and altered triggers
- PostgreSQL DROP TRIGGER includes the required ON table clause

### Stored Procedures / Functions

[](#stored-procedures--functions)

- Detects created, dropped, and altered routines (MySQL and PostgreSQL)
- SQLite has no stored procedures — routines are skipped automatically
- MySQL definitions are normalized (DEFINER, ALGORITHM, SQL SECURITY stripped)

### Enum Types (PostgreSQL)

[](#enum-types-postgresql)

- Detects created, dropped, and altered `CREATE TYPE ... AS ENUM` definitions
- ALTER = DROP TYPE IF EXISTS + CREATE TYPE with the new labels
- Enum diffs are ordered before table diffs (tables may reference enum types)
- MySQL and SQLite do not have standalone enum types — skipped automatically

### Data

[](#data)

- Compares table storage engine, collation, and row count
- Records changed rows and missing rows per table

Compatible Migration Tools
--------------------------

[](#compatible-migration-tools)

DBDiff supports multiple output formats via `--format`. Use `--description=` to customise generated filenames.

`--format`ToolLanguageOutputNotes`native` (default)Plain SQLAny`migration.sql`Up, down, or both`flyway`[Flyway](https://flywaydb.org)Java`V{ts}__{desc}.sql`Down adds `U{ts}__{desc}.sql` (Flyway Teams)`liquibase-xml`[Liquibase](https://liquibase.com)Java`changelog.xml`Both directions in one file`liquibase-yaml`[Liquibase](https://liquibase.com)Java`changelog.yaml`Both directions in one file`laravel`[Laravel Migrations](https://laravel.com/docs/migrations)PHP`YYYY_MM_DD_HHMMSS_{desc}.php``up()`/`down()` methods*(template)*[Simple DB Migrate](https://github.com/guilhermechapiewski/simple-db-migrate)PythoncustomUse `--template=templates/simple-db-migrate.tmpl`[Let us know](https://akalsoftware.com/) if you're using DBDiff with other tools so we can add them here.

Building a PHAR
---------------

[](#building-a-phar)

PHARs are built automatically and attached to every [GitHub Release](https://github.com/DBDiff/DBDiff/releases). 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.json` is pre-configured with GZ compression and `check-requirements: false` so the PHAR works correctly when stitched with the static micro SAPI runtime used in the pre-built binaries.

Releasing 🚀
-----------

[](#releasing-)

### Automated (recommended)

[](#automated-recommended)

1. Go to **GitHub Actions → Release DBDiff → Run workflow**
2. Enter the version number (e.g. `2.1.0` — no `v` prefix)
3. 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

[](#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
---------------------

[](#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: **5 PHP × 4 MySQL = 20 jobs**, plus dedicated jobs for SQLite, PostgreSQL, DSN URLs, and Supabase.

See [DOCKER.md](DOCKER.md) for flags covering fast restarts, recording fixtures, and CI usage.

Questions &amp; Support 💡
-------------------------

[](#questions--support-)

- Open a [new issue](https://github.com/dbdiff/dbdiff/issues/new/choose) or check [existing ones](https://github.com/dbdiff/dbdiff/issues)
- For commercial support enquiries, [get in touch](https://akalsoftware.com/)

Contributions 💖
---------------

[](#contributions-)

Please read the [Contributing Guide](https://github.com/dbdiff/dbdiff/blob/master/.github/CONTRIBUTING.md) before submitting a PR.

[![](https://camo.githubusercontent.com/fd662b08e30002a39a03dfff5c3ac8b95b2d9a43f80b2f013592cb6b45ecb643/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f636f6e7472696275746f72732f6462646966662f6462646966662e737667)](https://github.com/dbdiff/dbdiff/graphs/contributors)

Feedback 💬
----------

[](#feedback-)

Could you spare 2 minutes to share your feedback?

License
-------

[](#license)

[MIT](http://opensource.org/licenses/MIT)

Made with 💖 by
[![Akal Logo](images/akal-logo.svg)](https://akalsoftware.com/)

###  Health Score

62

—

FairBetter than 99% of packages

Maintenance87

Actively maintained with recent releases

Popularity54

Moderate usage in the ecosystem

Community27

Small or concentrated contributor base

Maturity67

Established project with proven stability

 Bus Factor1

Top contributor holds 85.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~651 days

Total

4

Last Release

86d ago

Major Versions

v1.0.0 → v2.0.02026-02-09

v2.0.0 → v3.0.0-rc.12026-04-03

PHP version history (2 changes)v2.0.0PHP &gt;=7.3

v3.0.0-rc.1PHP &gt;=8.1

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/12562465?v=4)[dbdiff](/maintainers/dbdiff)[@DBDiff](https://github.com/DBDiff)

---

Top Contributors

[![jasdeepkhalsa](https://avatars.githubusercontent.com/u/41632?v=4)](https://github.com/jasdeepkhalsa "jasdeepkhalsa (173 commits)")[![jawb](https://avatars.githubusercontent.com/u/1163113?v=4)](https://github.com/jawb "jawb (21 commits)")[![webian](https://avatars.githubusercontent.com/u/462601?v=4)](https://github.com/webian "webian (2 commits)")[![Copilot](https://avatars.githubusercontent.com/in/1143301?v=4)](https://github.com/Copilot "Copilot (2 commits)")[![desyncr](https://avatars.githubusercontent.com/u/1857707?v=4)](https://github.com/desyncr "desyncr (1 commits)")[![jijoel](https://avatars.githubusercontent.com/u/3487641?v=4)](https://github.com/jijoel "jijoel (1 commits)")[![plashenkov](https://avatars.githubusercontent.com/u/2331932?v=4)](https://github.com/plashenkov "plashenkov (1 commits)")[![amontalban](https://avatars.githubusercontent.com/u/941928?v=4)](https://github.com/amontalban "amontalban (1 commits)")

---

Tags

migrationmigrationsmysqlmysql-databasepostgrespostgresqlpostgresql-databasesqlitesqlite-databasesqlite3sqlite3-databasesupabasesupabase-db

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/dbdiff-dbdiff/health.svg)

```
[![Health](https://phpackages.com/badges/dbdiff-dbdiff/health.svg)](https://phpackages.com/packages/dbdiff-dbdiff)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[spatie/laravel-permission

Permission handling for Laravel 12 and up

12.9k102.4M1.4k](/packages/spatie-laravel-permission)[mongodb/laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel

7.1k8.4M95](/packages/mongodb-laravel-mongodb)[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45444.2k1](/packages/pressbooks-pressbooks)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9762.4M130](/packages/roots-acorn)[flarum/core

Delightfully simple forum software.

201.4M2.3k](/packages/flarum-core)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
