A cross-platform .NET 9 CLI tool that generates incremental PostgreSQL deployment scripts by comparing DDL folders.
pg-deploy compares a source folder (containing desired/new DDL) against a target folder (containing existing DDL extracted from a database) and produces a single SQL deployment script with only the changes needed to bring the target in line with the source.
Both folders should be in the format produced by pg-extract-schema, with subdirectories per object type (tables/, views/, functions/, etc.).
- Incremental changes only — uses
ALTERwhere possible instead ofDROP+CREATE - Smart column diffing — detects added/removed columns, type changes, default changes, nullability changes
- Potential rename detection — flags tables with both added and dropped columns as possible renames
- Destructive change control — drops require
--allow-dropsflag and are placed in a clearly-marked section - Transaction-wrapped — output script uses
BEGIN/COMMITfor atomic deployment - Type change warnings — flags potentially problematic data type changes with line numbers
- Git-aware — includes git branch and remote info in the script header when available
- Change summary — header lists counts of adds, modifies, and drops per object type
| Object Type | Add | Modify | Drop | Strategy |
|---|---|---|---|---|
| Extensions | ✅ | — | ✅ | CREATE EXTENSION IF NOT EXISTS / DROP EXTENSION |
| Schemas | ✅ | ✅ (owner) | ✅ | CREATE SCHEMA / ALTER SCHEMA OWNER TO |
| Types (enum) | ✅ | ✅ | ✅ | ALTER TYPE ADD VALUE for new labels |
| Types (composite/domain) | ✅ | ✅ | ✅ | DROP+CREATE (no ALTER support) |
| Sequences | ✅ | ✅ | ✅ | ALTER SEQUENCE for property changes |
| Tables | ✅ | ✅ | ✅ | ALTER TABLE for columns/constraints |
| Indexes | ✅ | ✅ | ✅ | DROP+CREATE (indexes are always recreated) |
| Foreign Keys | ✅ | ✅ | ✅ | DROP+ADD CONSTRAINT |
| Views | ✅ | ✅ | ✅ | CREATE OR REPLACE VIEW |
| Materialized Views | ✅ | ✅ | ✅ | DROP+CREATE (no REPLACE support) |
| Functions/Procedures | ✅ | ✅ | ✅ | CREATE OR REPLACE FUNCTION/PROCEDURE |
| Triggers | ✅ | ✅ | ✅ | DROP+CREATE TRIGGER |
dotnet build -c ReleaseThe executable will be at bin/Release/net9.0/pg-deploy.exe (Windows) or bin/Release/net9.0/pg-deploy (Linux/macOS).
pg-deploy --source <source-ddl-folder> --target <target-ddl-folder> --output <output-script.sql> [options]| Parameter | Alias | Required | Description |
|---|---|---|---|
--source |
-s |
Yes | Folder containing new/desired DDL files |
--target |
-t |
No | Folder containing existing DDL (extracted from DB). If omitted, generates a full creation script. |
--output |
-o |
Yes | Output path for the generated SQL script |
--allow-drops |
No | Enable destructive changes (default: off) | |
--trust-source-folder |
No | Skip untrusted-source warning prompt (required for non-interactive use) | |
--verbose |
-v |
No | Verbose console output |
--quiet |
-q |
No | Suppress all console output |
Generate a deployment script (safe mode — no drops):
pg-deploy -s ./new-ddl -t ./current-ddl -o ./deploy.sqlGenerate with destructive changes enabled:
pg-deploy -s ./new-ddl -t ./current-ddl -o ./deploy.sql --allow-dropsNon-interactive / CI usage (skip source trust prompt):
pg-deploy -s ./new-ddl -t ./current-ddl -o ./deploy.sql --trust-source-folderGenerate a full creation script (no target — all objects are created from scratch):
pg-deploy -s ./new-ddl -o ./create-all.sql --trust-source-folderVerbose output for debugging:
pg-deploy -s ./new-ddl -t ./current-ddl -o ./deploy.sql -v-
Extract current DDL from the database:
pg-extract-schema -h myhost -d mydb -o ./current-ddl -U myuser
-
Make your DDL changes in a separate folder (or use the DDL from a dev branch).
-
Generate the deployment script:
pg-deploy -s ./updated-ddl -t ./current-ddl -o ./deploy.sql --allow-drops
-
Review the generated script, paying attention to:
- Warnings in the header (type changes, potential renames)
- The destructive changes section at the bottom
-
Execute the script against your database:
psql -h myhost -d mydb -U myuser -f ./deploy.sql
The generated script includes:
-
Header comment with:
- Generation timestamp
- Source and target folder paths
- Git branch and remote info (if available)
- Change summary (counts per object type)
- Warnings for risky changes (with line numbers)
- Destructive change listing (with line numbers)
-
Body wrapped in
BEGIN/COMMITwith changes ordered by dependency:- Extensions
- Schemas
- Types
- Sequences
- Tables (columns, constraints, comments)
- Indexes
- Foreign Keys
- Views
- Materialized Views
- Functions/Procedures
- Triggers
-
Destructive changes section (when
--allow-dropsis used) — clearly marked at the bottom
- Source folder trust: DDL files from the source folder are embedded into the generated SQL script. Without
--trust-source-folder, the tool displays a warning and prompts for confirmation before proceeding. Always verify the provenance of your source DDL files. - CHECK constraint validation: CHECK constraint expressions are validated to reject semicolons outside string literals, preventing SQL injection via crafted constraint definitions.
- Review before executing: Always review the generated deployment script before running it against a production database.
See architecture.md for detailed documentation on the system design, data flow pipeline, component responsibilities, dependency ordering, and security architecture (including known vulnerabilities).
dotnet build
dotnet testSee LICENSE for details.