Skip to content

Compared with SchemaHero

Ptah Operator and SchemaHero both let a team declare a database schema as Kubernetes resources and have a controller change the database. Choose between them by what must hold between a reviewed plan and the statement that runs.

Ptah Operator binds an approval to the state of the database and refuses to run when that state has moved. SchemaHero binds an approval to the text of the SQL and runs that text. Most of the differences below follow from that.

We build Ptah Operator, so check the evidence. We ran released Ptah Operator 0.2.9 and SchemaHero 0.26.2 on one Kubernetes 1.37 cluster with PostgreSQL 17.11, each scenario in its own namespace and database, on November 6, 2026. Both connected as an ordinary login, and hand edits ran as a separate superuser. The comparison on the blog has the commands, the manifests and the recorded output for both sides.

SchemaHero generates SQL from a Table manifest and stores it in a Migration object in the cluster, so the reviewed SQL does not reach your repository. PtahMigration takes numbered SQL files from a ConfigMap, Git or an OCI artifact, and the database records each version it applied in schema_migrations. After we deleted a cluster and applied the same manifests to a new one, the operator read that history and ran nothing again. SchemaHero had no migrations and no record in the database.

Approvals are Kubernetes objects, so who approved is lost with the cluster in both products. Keeping that in the database is tracked. PtahSchema also computes its SQL and keeps its plans in the cluster.

What we tested SchemaHero 0.26.2 Ptah Operator 0.2.9
Where the reviewed SQL lives In a Migration object in the cluster In your repository, with PtahMigration
The cluster is lost No SQL and no record of what ran Files in the repository, history in the database, and the next plan starts from where the database stands
Renaming a column with data Lost the data and stopped halfway A reviewed RENAME COLUMN kept every row
The database changed after review Ran the old SQL, failed 32 times in three minutes, then applied it unattended once it could Refused before any statement ran and planned again
The spec changed again before approval Ran the replaced plan, so the database no longer matched the spec Refused the old fingerprint
Unattended removal of a column with data Dropped the column and its data Blocked the plan and kept the data
A hand edit to the database No migration and no log line in five minutes Reported in 81 seconds, by category, with a one-minute interval, except a table the login cannot read (tracked)
A statement that fails Retried 30 times in two minutes, then ran unattended once it could Warned in the plan, did not retry, and required a new approval
Who approved Recorded any name passed to --actor Recorded the Kubernetes identity, and can refuse the author
PostgreSQL objects in one desired schema No fields for check constraints, partial or expression indexes, enums, generated columns, row-level security, policies, comments or partitioning All of these created and converged, with a partitioned parent table only. A SQL schema file can declare PARTITION OF since Ptah v0.23.0 (stokaro/ptah#5506), after that run
A GIN index type: gin built a B-tree Built a GIN index
Adding a column beside a composite foreign key Also dropped and recreated the key One ADD COLUMN

These are the results of one run with PostgreSQL. They show what each product did in that scenario, and they are not a statement about every workload.

  • Exact-plan approvals: an approval is a Kubernetes object that names one plan, and admission records who created it. approvals.requireDistinctApprover refuses the author of the change.
  • A guard on unattended apply: applyPolicyGuard keeps apply: Always with the groups you name, and a plan that changes privileges waits for an approval even then.
  • Immutable delivery from an OCI artifact by digest, as well as from a ConfigMap or Git.
  • Ptah Console, an optional web console for approvers, developers, people on call and auditors.

kubectl schemahero install is one command with no values. From v0.2.10 a published release of this operator is one helm command with no values, with every image still pinned by digest, and a release before that takes four values from its release manifest. An install command in the plugin is tracked.

SchemaHero’s Database resource has connection types for PostgreSQL, MySQL, CockroachDB, TimescaleDB, SQLite, RQLite and Cassandra. We ran only PostgreSQL, so we state that list from its API. This operator supports PostgreSQL 17 and 18 and MySQL 8.4, and widening that is tracked. If your engine is outside this operator’s list, SchemaHero may be your only option of the two.

Run Try it locally to see the same behavior on a cluster of its own, or start with First schema on your own.