Skip to main content
Every diff compares two schema sources:
  • from: current state;
  • to: desired state.
A source is any PostgreSQL schema representation that supaschema can parse into a SchemaModel. Use the format <prefix>:<location>, such as dir:database/schemas. The configured migrationsDir is always a planning input for source intent and lineage proof. A matching migrations:<migrationsDir> reference can also supply the generation before-state for migration-first adoption; migration replay is never a generation target. Existing reviewed migrations form the source-intent corpus for row backfills, explicit DML/DO workflows, enum rewrite recipes, Vault references, workload-proven index intent, and provider bootstrap constraints. Generated migration lineage in that same directory proves the current migration-tree baseline. supaschema should model that intent and verify that baseline before blocking; when the intent or baseline proof is absent, the diagnostic should tell an agent where to declare or pin it.

Source reference

Directory

Syntax: dir:database/schemasSQL files on disk. The default --to source for most commands. supaschema recursively reads every .sql file in the specified path.

Git snapshot

Syntax: git:INDEX, git:HEAD, git:origin/main, git:abc1234Schema in the staged index or at any committed Git ref. supaschema reads the schemaPaths files without touching your working tree.

Live database

Syntax: database:$DATABASE_URLRead-only introspection of a live PostgreSQL connection. Use this for explicit inspect, verify, selfcheck, drift, target-safety, or catalog-snapshot workflows, not migration generation.

SQL dump

Syntax: dump:path/to/schema.sql, dump:-A single SQL file, or standard input (-). Useful for one-off analysis of pg_dump output.

Catalog snapshot

Syntax: catalog:path/to/snapshot.jsonA JSON file produced by supaschema inspect. Lets you compare against a saved point-in-time without a live database.

Empty baseline

Syntax: empty:A zero-object schema model. Useful for first migrations when there is no database and no valid Git baseline.

dir: files

Use dir: for schema files on disk. supaschema walks the directory, parses .sql files, and builds a SchemaModel from supported CREATE statements.
When to use it:
  • Local development — your schema files live in the repository alongside your application code.
  • Any command where the desired state is what you have currently checked out.
You can specify multiple schema directories using the schemaPaths key in supaschema.config.json for project-wide defaults so you don’t have to type the path on every command.

Directory layout example

supaschema does not care about subdirectories or file names — it reads everything recursively and merges the results into one SchemaModel.

git: refs

Use git: to read schema files from the staged index, a commit, branch, or tag. It does not modify your working tree. It does not need a database connection.
When to use it:
  • Sequential local changes — use git:INDEX as the proven before-state after supaschema sync stages a complete schema closure.
  • CI pull request checks — generate the migration that would be produced by merging this branch, and fail the pipeline if it contains unreviewed destructive operations.
  • Release diffs — quickly see what changed between two tagged versions.
  • Code review — produce a human-readable SQL diff alongside the file diff in your PR.
supaschema resolves git: refs against the repository that contains your schemaPaths. The working directory must be inside a Git repository, and the ref must be reachable (fetched). For remote refs like git:origin/main, run git fetch first in your CI step.

CI pipeline example


database: catalogs

Use database: to read a live PostgreSQL catalog. supaschema queries system catalogs and builds a SchemaModel from what is deployed. It does not execute DDL against a database: source.
When to use it:
  • Applied-state reconciliation — you have an existing database and want a migration from what is deployed to your declarative files.
  • Drift detection — check whether someone has made out-of-band changes directly on the server.
  • Generating a migration from scratch — when you have no prior snapshot, the live database is the most authoritative “from” state.
The DATABASE_URL you pass is used for introspection only. supaschema does not cache credentials or send them anywhere. However, treat this URL as a secret — pass it via environment variable rather than hard-coding it in scripts that end up in version control.

Connection string formats


dump: files

Use dump: for one SQL file, such as pg_dump --schema-only output. Pass a file path or - for standard input.
When to use it:
  • One-off analysis — you received a schema dump from a client or legacy system and want to diff it against your current declarative files.
  • Audit trails — archive periodic pg_dump snapshots and compare them over time.
  • Offline workflows — you have a dump but no live connection to the source database.
dump: sources are parsed through the same fail-closed extraction path as schema-tree SQL. Use a cleaned schema-only dump that omits SET statements, ownership comments, and other pg_dump preamble statements, or filter the dump before passing it to supaschema.

migrations: histories

Use migrations: when a project owns schema shape through reviewed migration files instead of a maintained declarative tree.
supaschema reads filename-sorted .sql files, replays supported DDL in memory, and emits a schema model without a database connection. The replay model is valid for types --from and as the diff/plan/sync before-state when it resolves to the configured migrationsDir. It is not a generation target, verify target, or drift target. A different migration directory fails with SUPA_MIGRATION_BASELINE_UNSUPPORTED; using replay as --to fails with SUPA_SOURCE_MIGRATIONS_TARGET_UNSUPPORTED. Replaying the configured migrationsDir rebuilds the before-state from the whole corpus, so it is its own baseline proof. It stays valid whether or not generated lineage is present, and whether or not hand-authored migrations follow the newest generated migration. The lineage checks that produce SUPA_MIGRATION_BASELINE_UNSUPPORTED and SUPA_MIGRATION_BASELINE_MISMATCH apply to snapshot sources such as git:, dir:, dump:, and catalog:, which must match a recorded generated baseline. Replay is fail-closed for shape-corrupting gaps. Missing directories, duplicate CREATE objects, absent non-optional DROP targets, absent non-ignored targets for supported ALTER statements, and absent enum neighbors raise SUPA_REPLAY_ORDER_GAP and return no objects. Unsupported top-level DDL, unsupported ALTER TABLE subtypes, unsupported DROP kinds, and unsupported rename targets raise SUPA_REPLAY_UNSUPPORTED and return no objects. For policies, replay supports only definition changes expressed by ALTER POLICY ... TO, USING, and WITH CHECK in existing reviewed migrations. Omitted clauses retain their current definition. Policy renames remain unsupported; this boundary does not imply support for every ALTER POLICY form. Replay skips configured managed or excluded schemas before planner input, so Supabase-managed history noise such as auth DDL can be omitted without emitting unknown shapes. Simple schema DDL inside idempotent DO blocks is replayed from the block body when it can be parsed; other data and control-plane statements remain outside the schema model. Generated migration lineage uses migration-baseline:<dir>@<version> as a display label. That label is not a runtime source; migrations:<dir> is the runtime typegen input.

catalog: snapshots

A catalog snapshot is JSON from supaschema inspect. It captures a SchemaModel and fingerprint at one point in time.
When to use it:
  • Drift detection without a second live connection — store the post-deploy snapshot in your repo and compare against it in CI instead of needing credentials to a second environment.
  • Reproducible comparisons — a catalog: file is deterministic and version-controllable, unlike a live database connection.
  • Debugging — share a catalog: file with a teammate so they can reproduce a diff locally without access to your database.

Common combinations

The table below summarises the most useful source pairings and the workflow each one powers.
Defaults come from supaschema.config.json. sources.from owns the source before-state, schemaPaths owns the desired after-state, and migrationsDir owns migration-derived source intent plus generated-lineage baseline proof for zero-source-flag commands. For generation, the scaffolded "auto" before-state first resolves git:INDEX when the latest generated migration is staged without worktree edits and its lineage matches the indexed schema fingerprint. It then tries valid git:HEAD and blocks if generated migrations prove a different baseline. empty: is only for a first migration with no existing migration corpus. A migrations: before-state must resolve to migrationsDir and replay without errors; keep generation targets and verify/drift sources on dir:, git:, dump:, catalog:, database:, or empty:.
Last modified on July 27, 2026