Skip to main content

Phase 1: Extract

The extractor connects to your PostgreSQL database and queries the system catalogs (pg_catalog) to build a complete schema representation.

What Gets Extracted

  • Tables - Columns, constraints, indexes, partitioning
  • Views - Regular and materialized views with definitions
  • Functions - All languages, with full body and attributes
  • Triggers - Table triggers with conditions
  • Types - Enums, composites, domains
  • Sequences - With ownership information
  • Extensions - Installed extensions
  • TimescaleDB - Hypertables, compression/retention policies, continuous aggregates

Excluded Schemas

System schemas are automatically excluded: Use --exclude-schema to exclude additional schemas (e.g., _prisma, supabase_*).

Phase 2: Parse

The parser reads your SQL files and converts them to the same JSON schema format as the extractor.

Supported SQL

pgtofu supports standard PostgreSQL DDL:

Type Normalization

Types are normalized for accurate comparison:

Phase 3: Diff

The differ compares the current schema (from extract) with the desired schema (from parse) to detect all differences.

Change Detection

For each object type, the differ:
  1. Builds maps by qualified name (schema.name)
  2. Detects additions (in desired but not current)
  3. Detects deletions (in current but not desired)
  4. Detects modifications (in both but different)

Change Severities

Safe Type Widening

These type changes are classified as SAFE:

View Comparison

View definitions are normalized before comparison to handle formatting differences (whitespace, case, aliases).

Phase 4: Generate

The generator creates golang-migrate compatible migration files from the detected changes.

Dependency Resolution

Changes are ordered using topological sort (Kahn’s algorithm):
  1. Extensions
  2. Custom types
  3. Sequences
  4. Tables
  5. Columns, constraints
  6. Indexes
  7. Views
  8. Functions
  9. Triggers
  10. TimescaleDB features
Deletions are ordered in reverse.

Generated DDL Features

  • Idempotent - Uses IF EXISTS/IF NOT EXISTS clauses
  • Transaction-wrapped - Grouped in BEGIN/COMMIT blocks when safe
  • Reversible - Both up and down migrations generated
  • Documented - Includes comments describing each change
  • Safe identifiers - All identifiers properly quoted

File Naming

Breaking Change Warnings

Schema File Organization

Recommended directory structure:
pgtofu discovers all .sql files recursively. The directory structure is for your organization only.

Best Practices

Include the table definition and its indexes in the same file for easier maintenance.
Use CONSTRAINT fk_orders_user FOREIGN KEY... instead of anonymous constraints for clearer migrations.
Commit schema files to git. They are the source of truth for your database structure.
Always run pgtofu diff before pgtofu generate to review changes.

See Also