PHPackages                             schema-keeper/schema-keeper - 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. schema-keeper/schema-keeper

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

schema-keeper/schema-keeper
===========================

Track PostgreSQL schema as one-file-per-object dumps. Detect drift in CI. Read-only — complements your migrations.

v4.0.1(2mo ago)136.1k1MITPHPPHP &gt;=7.4CI passing

Since Mar 22Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/dmytro-demchyna/schema-keeper)[ Packagist](https://packagist.org/packages/schema-keeper/schema-keeper)[ RSS](/packages/schema-keeper-schema-keeper/feed)WikiDiscussions master Synced 3w ago

READMEChangelog (4)Dependencies (11)Versions (14)Used By (0)

SchemaKeeper
============

[](#schemakeeper)

[![CI](https://github.com/dmytro-demchyna/schema-keeper/actions/workflows/ci.yml/badge.svg)](https://github.com/dmytro-demchyna/schema-keeper/actions/workflows/ci.yml)[![Latest Stable Version](https://camo.githubusercontent.com/0d68e07ccf2e8ba3e74f98d0832c06ffd77e01a3c6c2fa27111c6a46af143f8e/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f736368656d612d6b65657065722f736368656d612d6b65657065722e7376673f636f6c6f723d626c7565)](https://packagist.org/packages/schema-keeper/schema-keeper)[![Minimum PHP Version](https://camo.githubusercontent.com/204b1791e3a57f86a93de1422b2a6e584f5045431629c5b9abd4e28dbc8b5357/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344372e342d626c75652e737667)](https://php.net/)[![Minimum PostgreSQL Version](https://camo.githubusercontent.com/b0a5c0a25bca0e15da17351e4ed5f17955c9d3e5ce23ea71ae980d5a49af04d8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706f737467726553514c2d25334525334431302d626c75652e737667)](https://www.postgresql.org/)[![License](https://camo.githubusercontent.com/8aa801b70cfeedef73bc5ecb9c6c3b2372a9ee25da5dd72298c0a0e35c4b581f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f736368656d612d6b65657065722f736368656d612d6b65657065722e737667)](https://packagist.org/packages/schema-keeper/schema-keeper)

**Track your PostgreSQL database structure in a version control system.**

SchemaKeeper is a read-only tool that saves each tracked schema object as a separate file, so schema changes become small, reviewable diffs:

```
schemakeeper dump /path/to/dump     # dump structure to files
schemakeeper verify /path/to/dump   # verify files against database
```

```
/path/to/dump
├── extensions/
│   ├── pgcrypto.txt
│   └── btree_gist.txt
└── structure/
    ├── public/
    │   ├── tables/
    │   │   ├── users.txt
    │   ├── views/
    │   │   └── active_users.txt
    │   ├── materialized_views/
    │   │   └── monthly_stats.txt
    │   ├── functions/
    │   │   └── validate_email(text).sql
    │   ├── procedures/
    │   │   └── refresh_cache(int4).sql
    │   ├── triggers/
    │   │   └── orders.audit_trigger.sql
    │   ├── types/
    │   │   └── order_status.txt
    │   └── sequences/
    │       └── orders_id_seq.txt
    └── billing/
        ├── tables/
        │   └── invoices.txt
        └── functions/
            └── calc_tax(numeric).sql

```

Why not just migrations?
------------------------

[](#why-not-just-migrations)

- **Untracked changes**: A teammate runs `ALTER TABLE` directly in production. Migrations won't catch it. SchemaKeeper will.
- **Environment drift**: Staging has an extra index, dev is missing a trigger. You only find out when something breaks. SchemaKeeper surfaces every difference.
- **Schema review in PRs**: Migrations show *what you intended*. SchemaKeeper shows *what actually happened* — every column, constraint, and function definition. All reviewable in a normal `git diff`.

SchemaKeeper complements your migration tool, it doesn't replace it.

How is this different from `pg_dump -s`?
----------------------------------------

[](#how-is-this-different-from-pg_dump--s)

`pg_dump -s` is for *recreating* schemas. SchemaKeeper is for *tracking and reviewing* schema changes in Git.

- **One file per object.** `pg_dump -s` puts the entire schema into a single file. SchemaKeeper gives each object its own file, so changed objects show up as changed files in `git status`.
- **Built-in drift detection.** `schemakeeper verify` compares a live database against the committed dump and prints unified diffs.

Installation
------------

[](#installation)

### Requirements

[](#requirements)

- PHP &gt;= 7.4
- `ext-pdo` + `ext-pdo_pgsql`
- PostgreSQL 10+

### Composer

[](#composer)

```
composer require schema-keeper/schema-keeper
```

### PHAR

[](#phar)

```
wget https://github.com/dmytro-demchyna/schema-keeper/releases/latest/download/schemakeeper.phar
chmod +x schemakeeper.phar
./schemakeeper.phar --version
```

> **Note:** Examples below use `schemakeeper` as the command name. Replace with `vendor/bin/schemakeeper` or `./schemakeeper.phar` depending on your installation method.

Quick start
-----------

[](#quick-start)

**1. Dump your database**

```
schemakeeper dump /path/to/dump -h localhost -p 5432 -d mydb -U postgres
```

If the database requires a password, see [Password handling](docs/cli-reference.md#password-handling).

**2. Commit the result**

```
git add /path/to/dump
git commit -m "Add database structure dump"
```

**3. Add verification to CI**

Add `verify` to your CI pipeline (against the test database, after applying migrations). This ensures every migration is accompanied by an up-to-date dump:

```
- name: Verify database structure
  run: schemakeeper verify /path/to/dump -h localhost -p 5432 -d mydb -U postgres
  env:
    PGPASSWORD: ${{ secrets.DB_PASSWORD }}
```

Prefer PHPUnit over CLI? See [PHPUnit integration](docs/phpunit-integration.md) to run verification as a test.

**4. Monitor production for drift**

Run `verify` against your production database on a schedule to catch untracked DDL — the `ALTER TABLE` someone ran directly without a migration:

```
schemakeeper verify /path/to/dump -h prod-host -p 5432 -d mydb -U postgres
```

`verify` exits with code `1` on mismatch. Set it up as a cron job or a post-deployment step on any machine with database access.

What a failed verify looks like
-------------------------------

[](#what-a-failed-verify-looks-like)

When the database doesn't match the committed dump, `schemakeeper verify` prints unified diffs for every difference:

```
--- functions/public.func_sql_simple(integer, integer)
+++ functions/public.func_sql_simple(integer, integer)
@@ @@
 CREATE OR REPLACE FUNCTION public.func_sql_simple(a integer, b integer)
  RETURNS integer
  LANGUAGE sql
+ IMMUTABLE
 AS $function$
-   SELECT a + b;
+   SELECT a * b;
 $function$

--- /dev/null
+++ triggers/public.test_table.notify_on_update
@@ @@
+CREATE TRIGGER notify_on_update AFTER UPDATE ON test_table FOR EACH ROW EXECUTE FUNCTION trig_test()

--- types/public.test_enum_type
+++ types/public.test_enum_type
@@ @@
-{enum1,enum2}
+{enum1,enum2,enum3}
```

The diff shows:

- `func_sql_simple` gained `IMMUTABLE` and its body changed from `a + b` to `a * b`
- `test_table` got a new trigger `notify_on_update`
- `test_enum_type` got a new enum value `enum3`

Dump directory structure
------------------------

[](#dump-directory-structure)

See [File format reference](docs/file-formats.md) for tracked object types, file naming, and example output.

PHPUnit integration
-------------------

[](#phpunit-integration)

SchemaKeeper can also run as a PHPUnit test that fails on schema drift. See [PHPUnit integration](docs/phpunit-integration.md) for setup instructions.

CLI reference
-------------

[](#cli-reference)

See [CLI reference](docs/cli-reference.md) for the full list of options, filter flags, exit codes, and password handling.

Recommended workflow
--------------------

[](#recommended-workflow)

### Resolving merge conflicts

[](#resolving-merge-conflicts)

Different objects live in separate files, so changes to different objects auto-merge without conflicts.

When two branches modify the **same object**:

1. Merge the branch as usual
2. Accept either side of each conflict (`--ours` or `--theirs`)
3. Apply all migrations from both branches to your local database
4. Run `schemakeeper dump`
5. Commit the result

> The choice in step 2 doesn't matter — step 4 overwrites the files with the correct state.

### When verify fails

[](#when-verify-fails)

A failing `verify` means the database doesn't match the committed dump.

CauseFixForgot to dump after migrationRun `dump` and commit the updated filesUntracked DDL ran directly on databaseCreate a migration (or revert the change), then re-dumpStale dump after mergeRe-apply migrations and re-dump (see above)Environment-specific objectExclude it with `--skip-schema` or `--skip-section`Limitations
-----------

[](#limitations)

**Not tracked:**

- RLS policies
- Roles/permissions (GRANT/REVOKE)
- Rules
- Foreign data wrappers
- Publications/subscriptions
- Event triggers
- Operators and operator classes
- Aggregate and window functions
- Multirange types
- Comments (`COMMENT ON`)

**Procedures** require PostgreSQL 11+. On older versions, the procedures section is empty.

**Cross-version formatting:** Dumps are deterministic within a PostgreSQL major version. Some formatting may change after a PostgreSQL major upgrade.

Contributing
------------

[](#contributing)

Contributions are welcome. Please see [CONTRIBUTING.md](.github/CONTRIBUTING.md) for guidelines.

License
-------

[](#license)

MIT — see [LICENSE](LICENSE) for details.

###  Health Score

51

—

FairBetter than 95% of packages

Maintenance88

Actively maintained with recent releases

Popularity26

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity68

Established project with proven stability

 Bus Factor1

Top contributor holds 100% 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 ~215 days

Recently: every ~630 days

Total

13

Last Release

60d ago

Major Versions

v1.0.5 → v2.0.02019-05-10

v2.2.x-dev → v4.0.02026-04-11

PHP version history (2 changes)v1.0.1PHP &gt;=5.6

v4.0.0PHP &gt;=7.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/21a6b73c8d7e12d9488094805373ac03de6f8fd81470c8d734af757d9e3b952d?d=identicon)[dmytro-demchyna](/maintainers/dmytro-demchyna)

---

Top Contributors

[![dmytro-demchyna](https://avatars.githubusercontent.com/u/1595810?v=4)](https://github.com/dmytro-demchyna "dmytro-demchyna (115 commits)")

---

Tags

databasedatabase-reviewdiffdrift-detectiondumppgsqlpostgrespostgresqlpostgresql-cischemastructurediffschemadatabasedumppostgresqlpostgrespgsqlstructuredrift

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

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

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

###  Alternatives

[doctrine/dbal

Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.

9.7k595.8M6.5k](/packages/doctrine-dbal)[aura/sqlquery

Object-oriented query builders for MySQL, Postgres, SQLite, and SQLServer; can be used with any database connection library.

4563.1M37](/packages/aura-sqlquery)[aura/sqlschema

Provides facilities to read table names and table columns from a database using PDO.

41240.2k4](/packages/aura-sqlschema)[atlas/query

Object-oriented query builders and performers for MySQL, Postgres, SQLite, and SQLServer.

41253.7k7](/packages/atlas-query)[amphp/postgres

Asynchronous PostgreSQL client for Amp.

107557.2k36](/packages/amphp-postgres)[sad_spirit/pg_wrapper

Converter of complex PostgreSQL types and an OO wrapper for PHP's pgsql extension

2212.2k2](/packages/sad-spirit-pg-wrapper)

PHPackages © 2026

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