pgschema
differentiates itself from other declarative tools by:
pgschema
supports a wide range of Postgres features, including:
pgschema
is designed to work at the schema level.
public
schema. For these cases, schema-level operations eliminate unnecessary complexity while providing all the functionality needed for effective schema management.
Multi-Tenant Architecture Support: For applications using multiple schemas, the predominant pattern is schema-per-tenant architecture - where each customer or tenant gets their own schema within the same database. This schema-level approach enables tenant schema reconciliation - ensuring all tenant schemas stay in sync with the canonical schema definition.
Schema: -
in comments)users
instead of tenant_123.users
)public.user_role
for shared types)ALTER TABLE
statements, you write CREATE TABLE
definitions to specify the desired end state.
plan
and apply
phases creates a critical safety feature but also introduces a potential risk: what if the database changes between planning and execution? This time window could lead to applying outdated or conflicting migrations.
The tool solves this with fingerprinting - a cryptographic mechanism that ensures the exact database state you planned against is the same state you’re applying changes to.
pgschema plan
, it calculates a cryptographic fingerprint of the current database schema state and embeds it in the plan file:
pgschema apply
recalculates the current database fingerprint and compares it with the stored fingerprint from the plan.
CREATE INDEX CONCURRENTLY
to avoid blocking table writes:
pgschema:wait
directive blocks migration execution, polls the database to monitor progress, and automatically continues when operations complete.
For comprehensive details, see the Online DDL documentation.
can_run_in_transaction
field that indicates whether that particular SQL can run inside a transaction.
CREATE INDEX CONCURRENTLY
cannot run inside a transaction.
--multi-file
option:
main.sql
file serves as the entry point,
containing Postgres \i
(include) directives that reference individual component files.
triggers/audit.sql
might depend on a function in functions/timestamps.sql
, which itself references types defined in types/custom.sql
.
Database objects often depend on each other—triggers need functions, views reference tables, foreign keys require referenced tables to exist first. The tool automatically handles these dependencies using topological sorting to ensure operations execute in the correct order, regardless of how your schema files are organized.
pg_class
, pg_attribute
, pg_constraint
, etc.) and converted into the same normalized IR format.
3. Direct Comparison: The diff engine compares these two normalized IR structures directly, identifying what changes are needed without requiring any temporary databases.
4. Migration Generation: The differences are converted into properly ordered DDL statements that transform the current state into the desired state.
The IR normalization ensures that regardless of whether schema information comes from SQL parsing or database introspection, it’s represented consistently for accurate comparison - enabling precise migrations without the overhead and complexity of shadow databases.
pgschema
wouldn’t exist without these amazing open source projects: