pg-flux

Reference

Migration commands

pg-flux migrate generate / apply / rebase / status / repair / baseline / rollback.

#pg-flux migrate generate

Inspect the live database, diff against schema/, and write a timestamped .sql migration file.

Shell
pg-flux migrate generate [--label NAME] [--generate-undo] [--format separate|combined]
Flag Description
--dry-run Print the SQL to stdout without writing any file
--label <text> Appended to the timestamped filename: 20260520_103245_<label>.sql
--generate-undo Also write a best-effort reverse-migration as a separate _undo.sql file
--format <fmt> Migration file format: separate (default) or combined (single file with -- +migrate Up / -- +migrate Down sections)

The generated file embeds a pg-flux-baseline-hash header so apply can detect drift.

#Example

Shell
$ pg-flux migrate generate --label add_users_phone
Generated: migrations/20260520_103245_add_users_phone.sql (1 statement)

#pg-flux migrate apply

Apply all pending migration files in timestamp order.

Shell
pg-flux migrate apply [--dry-run] [--shadow-dsn URL] [--force-after-drift]
Flag Description
--dry-run Print what would be applied; touch nothing
--shadow-dsn <url> Optional disposable DB for pre-flight syntax / semantic validation
--force-after-drift Apply even if the baseline-hash drift check fails

Each migration runs inside a transaction (CONCURRENTLY statements run autocommit after). A session-level advisory lock prevents concurrent applies against the same database.

pg-flux retries acquisition for up to 30 seconds (1-second intervals). If it still cannot acquire the lock, the error message includes the exact SQL to release it manually:

SQL
SELECT pg_advisory_unlock(7040926865817495040);

#Example

Shell
$ pg-flux migrate apply
apply 20260520_103245_add_users_phone.sql ...
      ok
Applied 1 migration(s), 0 already up to date.

#pg-flux migrate status

Shell
pg-flux migrate status

Lists every file in migrations/ with its applied/pending state, apply timestamp, and whether Down SQL is available.

Shell
$ pg-flux migrate status
STATUS   FILENAME                                APPLIED AT                     DOWN
applied  20260518_140330_initial_schema.sql      2026-05-18 14:03:30.000000+00  no
applied  20260519_091012_add_posts_table.sql     2026-05-19 09:10:12.000000+00  yes
applied  20260520_103245_add_users_phone.sql     2026-05-20 10:32:45.000000+00  yes
pending  20260521_083011_add_audit_table.sql                                    yes

The DOWN column shows yes when the migration file contains a -- +migrate Down section (combined format) or a matching _undo.sql file exists (separate format).


#pg-flux migrate rollback

Roll back the last N applied migrations by executing the Down SQL embedded in each file and removing the tracking row.

Shell
pg-flux migrate rollback [N] [--dry-run]

N is a positional argument that defaults to 1.

Flag Description
--dry-run Print what would be rolled back without touching the database

Migrations are rolled back in reverse-apply order (most recent first). Migrations with no Down SQL are skipped with a tip message. If all requested migrations are skipped, pg-flux exits with code 6.

Each rollback runs inside a transaction. On failure the transaction is rolled back and the tracking row is left intact — the migration stays marked as applied.

#Examples

Shell
# Roll back the most recently applied migration
$ pg-flux migrate rollback
rollback 20260520_103245_add_users_phone.sql ...
         ok
Rolled back 1 migration(s).

# Roll back the last 3 migrations
$ pg-flux migrate rollback 3
rollback 20260520_103245_add_users_phone.sql ...
         ok
rollback 20260519_091012_add_posts_table.sql ...
         ok
rollback 20260518_140330_initial_schema.sql ...
         ok
Rolled back 3 migration(s).

See the Rollback guide → for full details on Down SQL formats, combined files, and limitations.


#pg-flux migrate rebase

Regenerate all pending (unapplied) migration files against the current live database state.

Shell
pg-flux migrate rebase

Use this after pulling a colleague's merged migrations that were applied to a shared environment while your own migrations were pending. Rebase keeps the original filenames (timestamps + labels) so ordering is preserved — only the SQL content and baseline hash are updated.

Situation What rebase does
One pending file Rewrites the file with new DDL (diff of desired schema vs. current live) and updates the baseline hash
Multiple pending files Folds all changes into the first file (earliest timestamp), removes the rest. Commit the deletions.
No pending files Prints "No pending migrations to rebase." and exits cleanly
Desired schema already matches live Marks the file(s) as unchanged — they will be no-ops when applied

#When to use rebase

The canonical signal that you need rebase is the drift error on migrate apply:

Text
Error: refusing to apply 20260601_100500_dev_b.sql: this migration was generated before
other changes were applied (expected baseline=1dcf92…, live=c28c4c…).
This is a parallel-development conflict: two branches were developed against the same
schema state and another branch was deployed first. To fix:
  1. Pull the latest migrations from your main branch.
  2. Run `pg-flux migrate apply` on your local DB to bring it up to date.
  3. Run `pg-flux migrate rebase` to regenerate this migration on top of current state.
  4. Commit the updated migration file and re-open your PR.

#Full rebase workflow

Shell
git pull origin main            # get the latest migrations from main
pg-flux migrate apply           # apply any new migrations to your local DB
pg-flux migrate rebase          # regenerate your pending migration
cat migrations/<your-file>.sql  # review the updated content
pg-flux migrate apply           # confirm it applies cleanly
git add migrations/
git commit -m "rebase migration"
git push

See Working in a team → for full parallel-branch scenarios.


#pg-flux migrate repair

Shell
pg-flux migrate repair

Recomputes the tracking-table checksum for every already-applied file. Use after intentionally editing an applied migration's content (e.g. fixing a typo in a comment).


#pg-flux migrate baseline FILE

Shell
pg-flux migrate baseline migrations/20260101_initial.sql

Marks a migration file as "already applied" without running its SQL. Used when adopting pg-flux against an existing database — the baseline file represents the starting state.