We've all been there. It's 2 AM, the deployment is failing, and you're staring at a migrations/ directory with a hundred sequentially numbered SQL files, trying to figure out which one you forgot to merge. Tools like Flyway and Liquibase imposed order on this mess, but they didn't eliminate the core drudgery: manually writing every ALTER TABLE.

pgschema promises to burn that playbook to the ground. It brings a declarative, Terraform-style workflow to your PostgreSQL database: instead of writing migration scripts, you maintain a single schema.sql file as your source of truth, and the tool diffs that file against the live database to generate the SQL.

The numbers say people are paying attention. At the time of writing it sits at 948 GitHub stars, ships version 1.11.0 (released June 9, 2026), and supports PostgreSQL 14 through 18. It is genuinely free under the Apache-2.0 license, with no feature gating and no open-core bait, and the commercial Bytebase platform foots the bill as sponsor.

I tested the workflow, and the core loop is seductively simple: dump the current schema, edit your schema.sql file, run plan to preview the changes, and apply to let it rip. For adding tables or columns, it is flawless.

Its real power lies in an obsessive focus on Postgres. I counted the object types straight from the README support table: 16 categories, from RLS policies and partitioned tables to partial indexes and SECURITY DEFINER functions. These are the exact details that generic, multi-database tools usually skip.

pgschema vs. The IncumbentspgschemaFlyway/LiquibaseAtlasWorkflowState-basedMigration-file-basedState-basedDatabase SupportPostgreSQL onlyMulti-databaseMulti-databaseShadow DatabaseNot requiredNot requiredRequired by defaultMigration History TablePostgres-specific ObjectsAuto-detectedManual SQLAuto-detected
Comparison data
pgschemaFlyway/LiquibaseAtlas
WorkflowState-basedMigration-file-basedState-based
Database SupportPostgreSQL onlyMulti-databaseMulti-database
Shadow DatabaseNot requiredNot requiredRequired by default
Migration History TableNoYesNo
Postgres-specific ObjectsAuto-detectedManual SQLAuto-detected
https://github.com/pgplex/pgschema ↗

One user on GitHub, who was looking to replace Atlas, praised this exact feature. For them, pgschema's ability to work without a shadow database removed a major headache from their complex environment.

But this beautiful simplicity is also a trap. The tool's core design principle is "no external state." That means no flyway_schema_history table to track what's been run. And more importantly, it means the tool has amnesia. It has no way to track developer intent beyond the schema itself. I checked the project's GitHub issues, and this purist design choice creates a loaded gun pointed directly at your data.

If you rename a column username to email in your schema.sql, pgschema doesn't see a rename. It sees that a column named username has vanished and a new one called email has appeared. The generated plan? DROP COLUMN username; ADD COLUMN email;. Just like that, all your user data is gone.

The stateless design produces this plan on purpose, and the maintainer confirmed that design is a core goal.

However, one of the design goal of pgschema is not leveraging external state such as refactor_log table mentioned here

tianzhou on GitHub

Another user even defended this dangerous behavior, arguing that adding any kind of manifest to track renames would defeat the entire purpose of the tool's spartan philosophy.

+1 really do not want to introduce (more) yaml to our workflows, if we started doing something with a log file + table there isn't a reason to use something like pgschema over other declarative (but non sql!) db management systems.

PadenZach on GitHub

This is not a forgotten corner of the backlog, either. A contributor opened pull request #435 in May 2026 to add automatic column-rename detection, exactly the safety net you would want. The maintainer closed it unmerged on May 30, calling the feature too heavyweight to maintain with confidence. The tracking issue #49 is still open and unresolved. I traced the whole thread: as of v1.11.0, a rename is still a DROP and an ADD.

The problems don't stop there. pgschema handles only DDL, the schema changes, and has no concept of DML, the data migrations. The maintainer confirmed in the feedback thread that data management is out of scope. Need to add a NOT NULL column and backfill it? You are forced into a fragile, manually orchestrated dance:

  1. Add the column as nullable in schema.sql and apply.
  2. Run your own separate, out-of-band script to populate the data.
  3. Change the column to NOT NULL in schema.sql and apply again.

This is worse than the old way. And with no migration history table, there's no audit trail and no true rollback. The "fix" for a bad migration is to revert your schema.sql and apply again, but that's a "roll-forward" that won't bring back the data you just accidentally dropped.

So who is this for? It's a genuinely useful tool for greenfield projects or simple internal apps where the schema only grows. But for any mature application that requires refactoring, data transformations, or an audit trail, pgschema's elegant design becomes a liability. It's a very sharp knife, but one that can't tell the difference between your schema and your data.