PostgreSQL quick start
Apply and verify a first Ptah schema change against a disposable PostgreSQL, from an empty directory to a column added and checked.
The same first result as the quick start, on the engine you are likely to use. You will start a throwaway PostgreSQL, apply a desired schema, ask for a column, review the SQL that change costs, apply it, and check the database agrees. Then you remove the database and nothing is left behind.
Take this one if you already know you are on PostgreSQL. Take the SQLite quick start if you want the shortest path with no Docker and no server at all; nothing here is different about Ptah, only about what it is pointed at.
What you need
Section titled “What you need”- A
ptahbinary on yourPATH. Install Ptah if you do not have one. - Docker, to run the disposable database. Nothing else is installed.
- A terminal and about ten minutes.
Confirm that the binary runs:
ptah versionStep 1. Start a database you can throw away
Section titled “Step 1. Start a database you can throw away”docker run -d --name ptah-quick-start \ -e POSTGRES_USER=ptah -e POSTGRES_PASSWORD=ptah -e POSTGRES_DB=app \ -p 55432:5432 postgres:18-alpinePort 55432 rather than 5432, so this cannot collide with a PostgreSQL you already run. The password is in the command because this database exists for the next ten minutes; a database you care about takes its URL from the environment or a secret store instead.
Wait until it is ready to accept connections:
docker exec ptah-quick-start pg_isready -U ptah/var/run/postgresql:5432 - accepting connectionsStep 2. Write the schema you want
Section titled “Step 2. Write the schema you want”mkdir ptah-postgres-quick-startcd ptah-postgres-quick-startcat > schema.sql <<'SQL'CREATE TABLE users ( id BIGSERIAL PRIMARY KEY, email TEXT NOT NULL);SQLexport DB='postgres://ptah:ptah@localhost:55432/app?sslmode=disable'New-Item -ItemType Directory ptah-postgres-quick-start | Out-NullSet-Location ptah-postgres-quick-start@'CREATE TABLE users ( id BIGSERIAL PRIMARY KEY, email TEXT NOT NULL);'@ | Set-Content schema.sql$DB = 'postgres://ptah:ptah@localhost:55432/app?sslmode=disable'schema.sql is the schema you want. The database is empty.
Step 3. See what that would cost
Section titled “Step 3. See what that would cost”ptah schema apply --schema-file schema.sql --db-url "$DB" --dry-runExpected output on standard output:
Planned schema changes:-- POSTGRES TABLE: users --CREATE TABLE "users" ( "id" BIGSERIAL PRIMARY KEY NOT NULL, "email" TEXT NOT NULL);--dry-run opens the database to read its current schema and executes no
planned statement. The SQL is PostgreSQL’s, rendered for this engine rather
than copied from the file.
Step 4. Apply it
Section titled “Step 4. Apply it”ptah schema apply --schema-file schema.sql --db-url "$DB" --auto-approveExpected output ends with, on standard output:
Auto-approval enabled; applying schema changes.Schema apply completed successfully.Step 5. Ask whether the database agrees
Section titled “Step 5. Ask whether the database agrees”ptah schema drift --schema-file schema.sql --db-url "$DB"No schema drift detected.That answer comes from reading the live database, not from the file. It is the check worth putting in a pipeline.
Step 6. Ask for a column
Section titled “Step 6. Ask for a column”Rewrite the schema you want. Nothing else changes:
cat > schema.sql <<'SQL'CREATE TABLE users ( id BIGSERIAL PRIMARY KEY, email TEXT NOT NULL, created_at TIMESTAMPTZ);SQL@'CREATE TABLE users ( id BIGSERIAL PRIMARY KEY, email TEXT NOT NULL, created_at TIMESTAMPTZ);'@ | Set-Content schema.sqlThe same check now has something to report:
ptah schema drift --schema-file schema.sql --db-url "$DB"Expected output includes, on standard output:
Schema drift detected (highest severity: warning).Findings:- columns_added: 1 (warning)And the plan is an ALTER, against the database as it is rather than as the
file describes it:
ptah schema apply --schema-file schema.sql --db-url "$DB" --dry-runExpected output ends with, on standard output:
ALTER TABLE "users" ADD COLUMN "created_at" TIMESTAMPTZ;Step 7. Apply the reviewed change, and check again
Section titled “Step 7. Apply the reviewed change, and check again”ptah schema apply --schema-file schema.sql --db-url "$DB" --auto-approveptah schema drift --schema-file schema.sql --db-url "$DB"No schema drift detected.The table now carries the column, and you can see it from PostgreSQL itself:
docker exec ptah-quick-start psql -U ptah -d app -c '\d users'Expected output includes, on standard output:
id | bigint | | not null | nextval('users_id_seq'::regclass) email | text | | not null | created_at | timestamp with time zone | | |Step 8. Remove it
Section titled “Step 8. Remove it”The database and the working directory, and nothing else:
docker rm -f ptah-quick-startcd ..rm -rf ptah-postgres-quick-startdocker rm -f ptah-quick-startSet-Location ..Remove-Item -Recurse -Force ptah-postgres-quick-startNext steps
Section titled “Next steps”- Evolve the schema and add a drift gate turns the check in step 5 into one a pull request fails on.
- Create and apply a versioned migration is the other route: files you review and replay rather than a plan derived each time.
- Choose a schema workflow before using a shared database.
- Adopt an existing database if yours already has tables in it.
- PostgreSQL is what this engine supports beyond the two statements above.