Skip to content
PtahPtah

Choose a workflow

For schema changes, wiring Ptah into a project answers two questions, and they are independent.

Persistent inference state follows a separate generation lifecycle. Start with Inference migrations.

Where does the change come from? Either you write the migration yourself — ptah migrations create, then the SQL — or you describe the schema you want and Ptah works out the difference. The first needs no schema source at all; the second reads one from SQL, YAML, HCL, or DBML files, Go annotations, an OCI artifact, or an external loader.

How does it reach the database? Either as versioned migration files that are reviewed, committed, applied in order and recorded in a revision table, or as a direct apply that computes the difference and executes it after approval.

Versioned files Direct apply
You write the migration migrations create, write the SQL, hash, upQuick start: versioned migrations
Ptah derives it from a desired schema migrations generate, then the same hash and up schema apply

The empty cell is not an omission: a direct apply computes a difference, and with no description of the schema you want there is nothing to compute one against. Everything else combines, and neither row is a reduced form of the other — a project can run for years on migrations it writes by hand and use every verb below except generate and plan.

The native ptah migrations namespace owns this workflow, and only two of its verbs read a desired schema. create scaffolds an empty *.up.sql/*.down.sql pair for you to fill in; generate writes the same pair from the difference between a desired schema and a database. From there the lifecycle is identical: hash seals the directory in the ptah.sum integrity file, up applies pending files in order and records each one in the revision table, down replays the committed rollback files, and status, validate, lint, import, checkpoint and the history verbs never ask what the schema should look like.

Terminal window
ptah migrations generate \
--schema-file schema.sql \
--db-url "$DATABASE_URL" \
--migrations-dir ./migrations \
--name add_orders
ptah migrations hash --dir ./migrations
ptah migrations up \
--db-url "$DATABASE_URL" \
--migrations-dir ./migrations \
--verify-sum

The migration directory lives in your repository, so every change is code-reviewed as SQL, and every environment replays the same files in the same order. Quick start: versioned migrations runs the hand-written half of this loop end to end.

If you arrived looking for a “declarative” workflow, this is it. Ptah does not use that word as the name, because ptah migrations generate reads the same desired schema and is not in this group: “declarative” names where a change came from, not how it lands. Direct schema changes sets out the distinction.

Native commands cover the whole loop: ptah db read prints a live schema, ptah schema compare shows how it differs from the desired schema, ptah schema drift turns that difference into a check that exits non-zero when the database has diverged, and ptah schema apply applies the planned change directly.

Terminal window
ptah schema drift --schema-file schema.sql --db-url "$DATABASE_URL"
ptah schema apply \
--db-url "$DATABASE_URL" \
--schema-file schema.sql \
--dry-run

With --dry-run, ptah schema apply prints the planned SQL under a Planned schema changes: heading and stops. Without it, the command shows the same plan and asks for approval before executing (--auto-approve skips the prompt). To separate review from execution, ptah schema plan writes a fingerprinted local plan file, and ptah schema apply --plan <path> runs it only while the database still matches the plan’s recorded starting state.

Question Versioned migrations Direct schema changes
Whether a desired schema is required No, except for generate and plan Yes
What gets reviewed Migration SQL committed to the repository Planned SQL at apply time, or a saved plan file
What records history Migration directory, ptah.sum, revision table Nothing; the live database is the only state
How rollback works ptah migrations down replays committed down files A new diff toward the schema you want back
Where it fits Shared and production databases, teams, CI gates Prototypes, local development, single-owner databases
Main commands ptah migrations ... ptah schema drift, ptah schema apply

The versioned workflow costs you a migration directory to maintain and the discipline of hashing and reviewing it. In exchange, changes are auditable, rollback is a committed file rather than an improvisation, and hashed directories verify integrity before anything touches a database, and --verify-sum additionally requires the sum file to exist. The direct workflow removes the file overhead and iterates fastest, but the apply-time approval is its only gate, and there is no history to replay or audit.

A common hybrid uses both: iterate with ptah schema apply against a disposable local database, then run ptah migrations generate against a database at the released state so the reviewed migration file — not the ad-hoc changes — is what reaches shared environments. In either model, ptah schema drift works as a pipeline guard that fails when a database no longer matches the desired schema.