Skip to content
PtahDocs
v0.8.1
Page type: how-to

YAML schema

Author the desired schema in Ptah's strict YAML format and feed it to render, compare, and migration commands.

Use YAML when Ptah owns the schema file and you want compact, explicit input without HCL syntax. The parser is strict: unknown keys fail instead of being silently ignored, so a typo cannot masquerade as an intentional setting.

Create schema.yaml:

tables:
accounts:
columns:
id:
type: SERIAL
primary: true
email:
type: VARCHAR(255)
not_null: true
indexes:
accounts_email_key:
fields: [email]
unique: true
extensions:
pgcrypto:
schema: extensions
if_not_exists: true

Preview the SQL Ptah derives before any database is involved:

Terminal window
ptah schema render --schema-file schema.yaml --dialect postgres

Expected output includes:

CREATE SCHEMA IF NOT EXISTS "extensions";
CREATE EXTENSION IF NOT EXISTS "pgcrypto" WITH SCHEMA "extensions";
CREATE TABLE "accounts" (
"id" SERIAL PRIMARY KEY NOT NULL,
"email" VARCHAR(255) NOT NULL
);
CREATE UNIQUE INDEX IF NOT EXISTS "accounts_email_key" ON "accounts" ("email");

The rendered SQL proves Ptah understood the desired schema. --schema-file is accepted wherever Ptah needs a desired schema: ptah schema render, ptah schema compare, ptah schema drift, the migration commands (ptah migrations plan / ptah migrations generate), and every target of ptah schema export except hcl. That includes the two documentation targets, so a Markdown or HTML reference can be generated from this file.

Path confinement is shared by every --schema-file source; see Schema file paths.

YAML can carry the API contract identity without changing the database identity. Tables accept api_name, openapi_name, graphql_name, and proto_name. Columns accept those four keys plus api_type and api_expose:

tables:
billing_invoices:
api_name: invoices
openapi_name: invoice_documents
graphql_name: invoice_records
proto_name: invoice_records
columns:
billing_amount_minor:
type: INTEGER
api_name: amount
openapi_name: amount_value
graphql_name: amountMinor
proto_name: amount_minor
api_type: TEXT
api_expose: read

The target-specific name wins over api_name, which wins over the database name. Table GraphQL and Protobuf values are type/message stems; column GraphQL and Protobuf values are exact field names. api_type changes only the generated contract type, and api_expose accepts read, write, read-write, or none. Invalid or unknown keys fail before output. See API schema export for target naming rules, collisions, and exposure behavior.

Everything a desired schema is for — comparing, gating on drift, generating migrations, applying directly, composing sources, validating across dialects — is the same for every source and lives on Work with a desired schema. For YAML the flag is --schema-file. Plan first, then generate files only after reviewing the plan:

Terminal window
ptah migrations plan \
--schema-file schema.yaml \
--db-url "$DATABASE_URL"
ptah migrations generate \
--schema-file schema.yaml \
--db-url "$DATABASE_URL" \
--migrations-dir ./migrations

Then seal and check the migration directory:

Terminal window
ptah migrations hash --dir ./migrations
ptah migrations validate --dir ./migrations