Every schema change has to land twice: once in a migration file somebody reviews, and once in a production database already serving traffic. The gap between those two is where the 2 a.m. ALTER TABLE lives, and code review does not close it.
On September 30, 2025, Liquibase moved its Community edition off Apache 2.0 and onto the Functional Source License, which reverts to Apache 2.0 two years after each release. On October 13, 2025, the Keycloak project opened a priority/blocker issue about it, noting that "CNCF does not permit source available licenses." That issue is still open as of September 14, 2026.
What Teams Actually Run
Most teams are not polyglot. In the 2025 Stack Overflow Developer Survey, 58.2 percent of professional developers reported using PostgreSQL, 39.6 percent MySQL and 30.9 percent Microsoft SQL Server. Multi-engine support is the headline feature of the enterprise tools and the feature most teams never use.
Volume follows the ORMs. In the week of September 5 to 11, 2026, npm served 13,644,360 downloads of drizzle-kit and 12,653,834 of prisma, against 3,843,592 for knex. Mindshare follows the standalone CLIs: GitHub stars on September 14, 2026 read golang-migrate 18,919, Bytebase 14,483, Flyway 10,085, Atlas 8,724, Liquibase 5,611 and Alembic 4,389. The two tools with the largest sales teams sit mid-list.
What a Migration History Table Cannot Tell You
Migration tools split into two models, and the split decides what yours can catch. Versioned tools such as Flyway, Liquibase and Alembic keep ordered scripts plus a history table of which ones ran. Declarative tools such as Atlas keep a description of the schema you want and diff it against the live database on every run.
A versioned tool is therefore blind to any change that did not arrive through it. This script shows the failure with no dependencies, on Node 22 or newer, which ships node:sqlite.
js// drift-demo.mjs - Node 22+, no dependencies. Run: node drift-demo.mjs import { DatabaseSync } from "node:sqlite" const MIGRATIONS = [ { version: "1", name: "init", sql: `CREATE TABLE customers (id INTEGER PRIMARY KEY, email TEXT NOT NULL);` }, { version: "2", name: "add_orders", sql: `CREATE TABLE orders (id INTEGER PRIMARY KEY, customer_id INTEGER NOT NULL, total_cents INTEGER NOT NULL);` }, ] function applyMigrations(db) { db.exec(`CREATE TABLE IF NOT EXISTS flyway_schema_history ( installed_rank INTEGER PRIMARY KEY, version TEXT, description TEXT, success INTEGER)`) const done = new Set(db.prepare(`SELECT version FROM flyway_schema_history`).all().map((r) => r.version)) for (const [i, m] of MIGRATIONS.entries()) { if (done.has(m.version)) continue db.exec(m.sql) db.prepare(`INSERT INTO flyway_schema_history VALUES (?, ?, ?, 1)`).run(i + 1, m.version, m.name) } return db } function schemaOf(db) { const tables = db.prepare( `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'flyway_%' AND name NOT LIKE 'sqlite_%'`, ).all() return new Map(tables.map((t) => [t.name, db.prepare(`PRAGMA table_info(${t.name})`).all().map((c) => `${c.name} ${c.type}`)])) } // 1. A real database: migrations applied, then a 2 a.m. hotfix nobody wrote a migration for. const live = applyMigrations(new DatabaseSync(":memory:")) live.exec(`ALTER TABLE orders ADD COLUMN discount_cents INTEGER NOT NULL DEFAULT 0`) // 2. What the migration files say the schema should be. const desired = applyMigrations(new DatabaseSync(":memory:")) console.log("versioned check - what the history table knows") for (const row of live.prepare(`SELECT version, description FROM flyway_schema_history ORDER BY installed_rank`).all()) { console.log(` V${row.version}__${row.description} applied`) } const pending = MIGRATIONS.length - live.prepare(`SELECT COUNT(*) c FROM flyway_schema_history`).get().c console.log(` status: ${pending === 0 ? "up to date" : pending + " pending"}, ${MIGRATIONS.length} of ${MIGRATIONS.length} applied\n`) console.log("declarative check - desired state vs live database") const [liveSchema, wantSchema] = [schemaOf(live), schemaOf(desired)] let drift = 0 for (const [table, wantCols] of wantSchema) { const liveCols = liveSchema.get(table) ?? [] for (const col of liveCols.filter((c) => !wantCols.includes(c))) { console.log(` ${table}: column "${col}" exists in the database but not in the migrations`) drift++ } for (const col of wantCols.filter((c) => !liveCols.includes(c))) { console.log(` ${table}: column "${col}" is in the migrations but missing from the database`) drift++ } } console.log(` status: ${drift} drift${drift === 1 ? "" : "s"} found`)
Run on September 14, 2026 with Node 25.5.0, it prints:
textversioned check - what the history table knows V1__init applied V2__add_orders applied status: up to date, 2 of 2 applied declarative check - desired state vs live database orders: column "discount_cents INTEGER" exists in the database but not in the migrations status: 1 drift found
Both checks ran against the same database. The history table reports a clean bill of health because every file it knows about ran, which is all it was designed to answer. Drift detection is the one feature worth paying for here, and it is why the commercial tiers exist.
Flyway
Flyway is the tool most teams mean when they say "just run the migrations": a Java CLI that executes numbered SQL files in order and records each in a flyway_schema_history table.

It stays out of the way. Name a file V2__add_orders_table.sql, put plain SQL in it, and Flyway runs it after V1__. No DSL, no abstraction to fight when you need a database-specific feature.
What it does not do is tell you the truth about drift for free. Drift detection, undo generation and policy enforcement are Enterprise features, and Teams carries a documented 100-schema cap. Redgate's editions page now positions Community as "for individuals and education," though the code on GitHub is still Apache 2.0.
Pricing: Community free · Teams paid, 100-schema cap · Enterprise contact sales. Apache 2.0, 10,085 stars, version 13.6.0 released September 10, 2026.
Liquibase
Liquibase takes the opposite bet: describe changes in a changelog, in XML, YAML, JSON or SQL, and let it generate the engine-specific statements.

The abstraction earns its keep if you genuinely ship to several engines, and the matrix is the widest here at 65 or more databases by the vendor's count. Rollback is a first-class concept rather than a paid add-on, which matters where an auditor wants a reversal path.
The problem is the license. Community 5.0 moved to the Functional Source License 1.1 with an Apache 2.0 future grant, which is source-available, not open source. You can run it in production free and fork it, but each release stays restricted for two years. Keycloak's blocker issue lists its options as switching components, freezing at the last Apache-licensed version, or forking.
Pricing: Community free · Liquibase Secure contact sales. FSL-1.1-ALv2, 5,611 stars, version 5.0.4 released August 20, 2026.
Atlas
Atlas is the declarative option. Write the schema you want in HCL, plain SQL or an ORM's models, and Atlas plans the migration by diffing it against the live database.

This is the Terraform model applied to schemas, so the drift check demonstrated above is a normal part of the workflow rather than an upsell. Atlas also lints planned changes, so a migration that would lock a large table fails in CI instead of production.
What it does not do is fit how most teams already work. Adopting it means giving up hand-written migration files as the source of truth, and free Starter is limited to MySQL, MariaDB, PostgreSQL and SQLite with limited inspection and diffing.
Pricing: Starter free · Pro from $9 per developer per month, plus $59 per month per CI/CD project and $39 per monitored database · Enterprise custom. Apache 2.0, 8,724 stars, version 1.3.0 released August 2, 2026.
Bytebase
Bytebase is not really a migration engine. It is the review queue, approval workflow and audit trail wrapped around one.

If your last outage happened because someone ran SQL directly against production, this is the category that fixes it. Bytebase puts a change request in front of a reviewer, runs SQL review rules against the statement, records who approved what, and handles just-in-time database access.
What it does not do is replace Flyway or Alembic inside your repository. It is a platform to stand up and operate, and 20 users is where the free tier stops being enough for a company that needs it. The core is MIT, but anything under an enterprise directory, including the code gating features by plan, is separately licensed.
Pricing: Community free, up to 20 users and 10 instances · Pro $20 per user per month · Enterprise custom. MIT core, 14,483 stars, version 3.22.1 released September 10, 2026.
Prisma Migrate
Prisma ORM ships migrations as part of the ORM. Edit schema.prisma, run prisma migrate dev, and Prisma writes the SQL by diffing the model against the database.

The generated file is editable SQL, so you get the authoring convenience of a declarative tool and the reviewable artifact of a versioned one. Prisma also refuses to apply a migration it judges destructive without explicit acknowledgment.
What it does not do is help anyone outside TypeScript, and the version situation needs care. Prisma ORM 8 is a release candidate with general availability expected in October 2026, and $extends, most nested writes and the familiar P2002 error codes are not in it yet. Version 7 keeps bug fixes and security updates for 18 months after 8 ships.
Pricing: Free. Apache 2.0, 47,607 stars on prisma/orm, stable version 7.10.0 released August 25, 2026.
Alembic
Alembic is what Python teams already have. Written by the author of SQLAlchemy, it autogenerates migration scripts by comparing your models against the connected database.

Autogenerate is the feature that matters. It drafts the migration, and because the output is a Python file you can add backfills, conditional logic and batch operations for SQLite in the same revision. Branch merge points are handled explicitly, which is more than most CLIs offer.
What it does not do is guess correctly every time. The documentation is direct that autogenerate misses some changes, table and column renames among them, so a generated revision needs reading. There is no UI, no approval workflow and no drift reporting beyond what you write.
Pricing: Free. MIT, 4,389 stars, version 1.20.0 released September 11, 2026.
Side by Side
| Tool | Model | Entry price | Drift detection | License |
|---|---|---|---|---|
| Flyway | Versioned SQL | Free Community | Enterprise only | Apache 2.0 |
| Liquibase | Versioned changelog | Free Community | Paid tier | FSL-1.1-ALv2 |
| Atlas | Declarative | $9/dev/month | Built in | Apache 2.0 |
| Bytebase | Governance platform | $20/user/month | Built in | MIT core |
| Prisma Migrate | ORM-integrated | Free | No | Apache 2.0 |
| Alembic | ORM-integrated | Free | No | MIT |
How to Choose Without Migrating Twice
- Count your engines before buying for many. Run the vendor matrix against the databases you actually deploy. If the answer is one, Liquibase's multi-engine abstraction is cost for nothing.
- Run the drift script above against real staging. Point it at a schema you believe is clean. Nothing found means versioned migrations are enough. Anything found is a governance problem no migration tool fixes alone.
- Check your license policy before the feature list. If you redistribute the tool, or follow CNCF or Apache policy, the Liquibase FSL change settles the question without a comparison.
- Decide who may touch production. If the honest answer is "several people, directly," you need an approval queue more than a better migration file format.
- Try the rollback before you need it. Apply a migration, reverse it, and time the reversal on realistic row counts. Undo is paid in Flyway and free in Liquibase and Alembic, and that gap only shows up under pressure.
Which One Should You Actually Use?
Single Postgres or MySQL database, small team: Flyway Community. Plain SQL, Apache 2.0, no platform to operate. Add the drift script to a nightly CI job and you have covered most of what the paid tier sells.
Already on Prisma or SQLAlchemy: use Prisma Migrate or Alembic and stop shopping. A second migration tool means two sources of truth for one schema. Pin Prisma to the 7 line until ORM 8 is generally available.
Schema changes cause your incidents: Atlas. Declarative diffing plus migration linting catches locking and destructive changes before production, and $9 per developer per month is cheaper than one postmortem.
Auditors and several engines: Liquibase Secure if your license policy permits FSL, Bytebase if it does not. Both give an approval trail; only Bytebase keeps an MIT core.
Direct production access is the real problem: Bytebase, whichever engine you keep underneath. It solves a different problem than the rest of this list.
Conclusion
What changed this year is not a feature, it is a license. Liquibase leaving Apache 2.0 removed the obvious open-source answer for multi-engine migrations, and the remaining permissive options are either single-purpose CLIs such as golang-migrate 4.20.1 and goose 3.28.0, or declarative tools such as Atlas that ask you to change how you work. Before renewing anything here, ask one question: if someone changes production by hand tonight, which of these tells me tomorrow morning? On the free tier, for most teams, the answer is none of them.
Related DevToolLab Tools
- SQL Create Table Generator - draft the DDL for a first migration from column definitions instead of finding the typo in CI.
- SQL Formatter - normalize migration SQL to one style so a code review shows the schema change, not somebody's indentation.
- SQL Query Explainer - read the plan after an index migration to confirm the new index is actually used.
- SQL Insert Generator - build the seed and backfill statements that ride along with a schema change, from JSON you already have.
Related Guides
- Best Serverless Postgres in 2026 - where the database you are migrating probably runs, and what scale-to-zero does to a long migration.
- SQL Formatting Best Practices - the conventions that make a migration file reviewable by someone who did not write it.
- Best CI/CD Tools in 2026 - the pipeline that has to run these migrations, and what the minutes cost.
- Best Infrastructure as Code Tools in 2026 - the same declarative-versus-imperative argument, one layer down.
