pgschema picks migration strategies that minimize downtime and blocking when making schema changes to production PostgreSQL databases.
Index Operations
Adding Indexes
When adding new indexes,pgschema automatically uses CREATE INDEX CONCURRENTLY to avoid blocking table writes:
pgschema:wait directive blocks the schema migration execution, polls the database to monitor progress, displays the progress to the user, and automatically continues when the operation completes. It tracks:
- Completion status: Whether the index is valid and ready
- Progress percentage: Based on
pg_stat_progress_create_index
Modifying Indexes
When changing existing indexes,pgschema uses a safe “create new, drop old” pattern:
- No downtime during index creation
- Query performance is maintained throughout the migration
- Rollback is possible until the old index is dropped
Constraint Operations
Supported constraint types:- Check constraints: Data validation rules
- Foreign key constraints: Referential integrity with full options
- NOT NULL constraints: Column nullability (via check constraint pattern)
ADD ... NOT VALID and VALIDATE CONSTRAINT statements in separate transactions. This matters: the lock taken by ADD CONSTRAINT is released before validation starts, so the long table scan performed by VALIDATE runs under a weaker lock that does not block reads or writes.
CHECK Constraints
Constraints are added using PostgreSQL’sNOT VALID pattern:
Foreign Key Constraints
Foreign keys use the sameNOT VALID pattern:
NOT NULL Constraints
On PostgreSQL 18+, pgschema uses the native invalidNOT NULL constraint support:
NOT NULL column in CREATE TABLE, so the migrated table converges with a freshly created one.
If the VALIDATE step never ran (an interrupted apply, or a NOT VALID constraint added by hand), the column already reads as NOT NULL in the catalog, but existing rows are unchecked. pgschema detects the unvalidated constraint on the next plan and emits just the VALIDATE CONSTRAINT step, so the migration can be finished by re-applying.
On PostgreSQL 14-17, adding NOT NULL uses a check constraint based process:

