Design Record: Why an Execution Fabric#

Status: FOUNDATIONAL — the product boundary. The reader-facing comparison lives in Why pgmi ; this page records the decision and its deliberate omissions.

Decision#

pgmi is an execution fabric: it prepares a session and executes the project’s SQL, and the project’s SQL owns every deployment semantic — selection, ordering, transactions, tests, idempotency, retry. It is not a migration framework, where those semantics belong to the tool:

Fabric versus framework: a migration framework’s model owns ordering, history, and transactions; in pgmi, your deploy.sql defines the semantics

What pgmi deliberately does not do#

Each omission is a decision, not a gap — and each has a documented home on the SQL side:

  • No version/history table. Tracking is a choice you implement (the advanced template ships a complete one).
  • No tool-imposed execution order. The plan is a derived, queryable view ; your deploy.sql decides what to run and in which order.
  • No retry logic or error taxonomy. Errors are raw PostgreSQL errors with numbered exit codes ; retry policy belongs to the layer that owns the transaction.
  • No implicit idempotency. CREATE OR REPLACE, IF NOT EXISTS, and checksum-tracking patterns are yours to apply — pgmi will faithfully re-run whatever you give it.
  • No daemons, schedulers, or servers in the deployment path. One invocation, one session, one exit code.

The one place pgmi’s Go code reads your SQL to decide how to execute it — the first top-level transaction terminator that splits atomic head from psql-mode tail — is deliberately a ceiling, not a precedent: one token class, read to preserve PostgreSQL’s own semantics, never to add pgmi’s.

Rejected alternative#

The framework model itself. A version table, up/down pairs, tool-owned transaction boundaries, and flags for behavior were the obvious design — every major tool in the space works that way, and users arrive expecting it. It was rejected because the framework’s model is a fixed vocabulary: anything it didn’t anticipate (test-gated commits, data-dependent branching, multi-phase ordering , interleaved concurrent-index builds) becomes a feature request. Making the deployment a PostgreSQL program makes those the user’s ordinary SQL instead. The cost is recorded, not hidden: PL/pgSQL expertise is required , and pgmi is overkill for some projects .

The contract that makes it safe#

A fabric without a stable surface would couple every project to pgmi internals. The versioned session API is the counterpart decision: internal _pgmi_* tables stay free to change, public pgmi_*_views are the contract — drawn in the session API surface diagram .

See also#