Skip to main content

schemadrift

Detect schema drift between PostgreSQL databases and generate safe, ordered migration SQL — from the command line.

CI PyPI version Python versions License: MIT


Features

  • 🔍 Schema inspection — Introspects live PostgreSQL databases via psycopg2 (tables, columns, indexes, foreign keys, enums)
  • 🔄 Drift detection — Pure-Python diff engine with zero database dependency for the comparison step
  • 📝 Safe SQL generation — Produces BEGIN/COMMIT-wrapped migration scripts in the correct dependency order (drop FKs first, create tables before adding columns, etc.)
  • 🖥️ Rich CLI — Beautiful terminal output powered by Rich
  • 📦 Multiple output formats — SQL, JSON, or human-readable summary
  • ✅ 95%+ unit test coverage — All core logic tested without a live database

Installation

pip install schemadrift

Or install from source:

git clone https://github.com/Asadshah7950/schemadrift.git
cd schemadrift
pip install -e '.[dev]'

Quick Start

Python API

from schemadrift.inspector import SchemaInspector
from schemadrift.differ import SchemaDiffer
from schemadrift.generator import MigrationGenerator

# Introspect both databases
source = SchemaInspector("postgres://user:pass@source-host/mydb").snapshot()
target = SchemaInspector("postgres://user:pass@target-host/mydb").snapshot()

# Compute the diff
diff = SchemaDiffer(source, target).diff()

# Generate migration SQL
sql = MigrationGenerator(diff).generate()
print(sql)

Output example

BEGIN;

-- Drop foreign key: fk_orders_user
ALTER TABLE "orders" DROP CONSTRAINT "fk_orders_user";

-- Add table: payments
CREATE TABLE "payments" (
    "id" integer NOT NULL,
    "amount" numeric NOT NULL,
    PRIMARY KEY ("id")
);

-- Add column: users.phone
ALTER TABLE "users" ADD COLUMN "phone" text;

-- Add foreign key: fk_orders_user
ALTER TABLE "orders" ADD CONSTRAINT "fk_orders_user"
  FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE NO ACTION;

COMMIT;

CLI Usage

diff — Compare two schemas

# Print migration SQL to stdout
schemadrift diff \
  --source "postgres://user:pass@source-host/db" \
  --target "postgres://user:pass@target-host/db"

# Save to a file
schemadrift diff \
  --source "postgres://user:pass@source-host/db" \
  --target "postgres://user:pass@target-host/db" \
  --output migration.sql

# JSON output
schemadrift diff \
  --source "postgres://user:pass@source-host/db" \
  --target "postgres://user:pass@target-host/db" \
  --format json

# Human-readable summary
schemadrift diff \
  --source "postgres://user:pass@source-host/db" \
  --target "postgres://user:pass@target-host/db" \
  --format summary

# GitHub Actions / PR Markdown report
schemadrift diff \
  --source "postgres://user:pass@source-host/db" \
  --target "postgres://user:pass@target-host/db" \
  --format markdown >> $GITHUB_STEP_SUMMARY

# CI/CD Gate: Fail pipeline (exit code 1) if schema drift is detected
schemadrift diff \
  --source "postgres://user:pass@source-host/db" \
  --target "postgres://user:pass@target-host/db" \
  --fail-on-drift

# Rollback / down migration (revert target back to source)
schemadrift diff \
  --source "postgres://user:pass@source-host/db" \
  --target "postgres://user:pass@target-host/db" \
  --direction down \
  --output rollback.sql

# Non-transactional execution (omit BEGIN / COMMIT)
schemadrift diff \
  --source "postgres://user:pass@source-host/db" \
  --target "postgres://user:pass@target-host/db" \
  --no-transaction

# Zero-downtime index management (CREATE / DROP INDEX CONCURRENTLY)
schemadrift diff \
  --source "postgres://user:pass@source-host/db" \
  --target "postgres://user:pass@target-host/db" \
  --concurrently

inspect — Print a schema overview

schemadrift inspect --dsn "postgres://user:pass@host/db"

Output:

              Schema Summary
┌──────────────┬─────────┬─────────┐
│ Table        │ Columns │ Indexes │
├──────────────┼─────────┼─────────┤
│ orders       │       6 │       3 │
│ payments     │       4 │       1 │
│ users        │       8 │       4 │
└──────────────┴─────────┴─────────┘
Foreign keys: 2

Architecture

Module Description
schemadrift/models.py Dataclasses for all schema objects (ColumnDef, TableDef, IndexDef, ForeignKeyDef, SchemaSnapshot, DiffResult)
schemadrift/inspector.py SchemaInspector — connects to PostgreSQL and builds a SchemaSnapshot using information_schema and pg_catalog queries
schemadrift/differ.py SchemaDiffer — pure-Python comparison engine; no DB connection required
schemadrift/generator.py MigrationGenerator — converts a DiffResult into safe, ordered SQL wrapped in a transaction
schemadrift/cli.py Click CLI exposing diff and inspect commands with Rich terminal output

Contributing

Contributions, bug reports, and feature requests are welcome! See CONTRIBUTING.md for development setup instructions.


License

MIT © 2024 Asad Shah

Release files for pg-schema-diff 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pg-schema-diff 0.2.0
File Size Uploaded
pg_schema_diff-0.2.0.tar.gz 17.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pg-schema-diff 0.2.0
File Interpreter ABI Platform
pg_schema_diff-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 31.0 kB

Release files / pg_schema_diff-0.2.0.tar.gz

Download URL pg_schema_diff-0.2.0.tar.gz
Size 17.3 kB
Tags Source
SHA-256 checksum
How to use checksums
72db44ae53299ed14fd3d9e91c837a5a83da86ff840361c2b609a379bf2f3457
BLAKE2b-256 checksum
How to use checksums
906146715c1eb8f307a99e740426f31376ed3c2f0329ead460da1b23feba4057
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / pg_schema_diff-0.2.0-py3-none-any.whl

Download URL pg_schema_diff-0.2.0-py3-none-any.whl
Size 13.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9b4ce20cff54fc032d2a9f7a37f808ab5e8821b533908b8ba8d97032c3705329
BLAKE2b-256 checksum
How to use checksums
a742eec634dbaef76d09e107dc3520d9e5b1f47da94c6f6d88a3b311689c2433
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page