A small, focused PostgreSQL migration toolkit.
You write SQL describing the exact desired state of your database in an
ordered sql/ directory. pgpkg does everything else:
stageversion— concatenatessql/into a versioned base file<prefix>--<version>.sql.makemigration— diffs two staged versions with results to generate an incremental migration<prefix>--A--B.sql.graph— shows the version graph and shortest paths between versions.migrate— connects to a live database (libpq env vars or psql-style flags), reads the currently installed version, and applies the shortest sequence of incrementals (or bootstraps from a base file) to reach the target version.wheel— scaffolds a self-contained wrapper Python project that bakes your migrations into a wheel and exposes a<project>-migratorconsole script.verify— round-trips every edge(a -> b)through two throwaway databases to prove the incremental produces the same schema as loading<prefix>--b.sql.bundle— writes a compressedtar.zstartifact containingmigrations/plussql/pre/andsql/post/for automation or custom packaging flows.
- Python ≥ 3.11 and uv
pgpkg[diff]— themakemigrationcommand requires the optional results dependency:uv tool install --with 'pgpkg[diff]' pgpkg- Docker —
makemigrationandverifyspin up throwaway PostgreSQL containers viatestcontainers; Docker must be running - libpq —
migrateconnects to a live database using standard libpq environment variables (PGHOST,PGPORT,PGDATABASE,PGUSER,PGPASSWORD) or explicit-h/-p/-d/-U/--dsnflags
uv tool install --with 'pgpkg[diff]' pgpkg
mkdir -p sql/pre sql/post
echo "CREATE TABLE foo (id int PRIMARY KEY);" > sql/010_schema.sql
# declare your project once
cat >> pyproject.toml <<'TOML'
[tool.pgpkg]
project_name = "myext"
TOML
# stage a version
pgpkg stageversion 0.1.0
# iterate sql/ and generate an incremental
pgpkg stageversion 0.2.0
pgpkg makemigration --from 0.1.0 --to 0.2.0
# apply to a live database (libpq env vars honored)
pgpkg migrate -d mydb -h localhost --to 0.2.0By default, pgpkg records applied versions in pgpkg.migrations. You can
relocate that table with:
[tool.pgpkg]
project_name = "myext"
[tool.pgpkg.tracking]
schema = "ops"
table = "schema_versions"If your application already owns the authoritative version table, set
[tool.pgpkg].version_source = "module:attribute" and provide an object with
read_live_version(...) and record_applied(...) methods. The generic
pgpkg wheel scaffold is intentionally limited to the default tracking path;
custom version sources should use a project-specific wrapper that calls
pgpkg.api.migrate_from_artifact(..., version_source=...).
See the full manual at https://bitner.github.io/pgpkg/ and the source docs in docs/.
uv sync --extra dev --extra diff
uv run pre-commit install
uv run pre-commit run --all-files
uv run ty check src tests
uv run pytest -q
uv build --out-dir dist
uv run mkdocs build --strictSee CONTRIBUTING.md for the release workflow and trusted-publishing setup. For initial repository and publishing bootstrap, use your local project bootstrap checklist.
MIT