✍️ 필사 모드: DB Migration Tools 2026 — Atlas, Bytebase, Skeema, Liquibase, Flyway, Prisma, Drizzle, gh-ost, pg-osc Deep Comparison (Declarative vs Imperative, Review Workflow, Online DDL)
EnglishPrologue — Why migration tools are still hard
Database schema change is one of the riskiest tasks in software. A code deploy is easy to roll back; an ALTER TABLE becomes a fact on disk the moment it runs. Lock a large table wrong and your service goes down.
That is why migration tools exist. But as of May 2026, the category is more fragmented than ever.
- Liquibase and Flyway were the de facto standards in the Java world from the 2010s onward and are still the enterprise default.
- Prisma Migrate and Drizzle Kit have settled in as the default for TypeScript apps. Bundled with the ORM, they are the smoothest.
- Atlas (Ariga) is rapidly gaining share with HCL-based declarative schema-as-code. Schema Monitoring, Schema Lint, and Versioned Migrations — all in one tool.
- Bytebase made the review workflow a first-class citizen. Multi-DB, GitOps, plus an AI assistant.
- Skeema survived as the lightest declarative tool in the MySQL world and now supports Postgres.
- And large live tables still need online DDL tools like gh-ost, pt-online-schema-change, and pg-online-schema-change.
This article compares these tools along the axes of declarative vs imperative, review workflow, drift detection, multi-DB, AI assistance, and online DDL safety. It walks real scenarios — adding a column, introducing NOT NULL, large-table backfill, rolling rename — for each tool and ends with a per-team decision framework.
This is a tool comparison, not a pattern guide. The zero-downtime expand-contract pattern itself is covered in a separate post (see
2026-04-15 zero-downtime database migration). Here the focus is which tool drives which pattern, and how.
1. The Landscape — A Map of Tools
A taxonomy first. It does not fit in one line.
| Category | Tools | One-liner |
|---|---|---|
| Declarative schema-as-code | Atlas, Skeema, Drizzle Kit | You write the desired state, the tool computes the diff |
| Imperative migration-files | Liquibase, Flyway, Prisma Migrate, dbmate, Sqitch | You write what changes, one file at a time |
| Review-workflow-first | Bytebase, Atlas Cloud | PR, approval, rollback, execution in one screen |
| Online DDL (large tables only) | gh-ost, pt-online-schema-change, pg-online-schema-change | Shadow table + triggers + cutover |
| Managed cloud | Atlas Cloud, Bytebase Hub, Liquibase Hub | Execution logs, approvals, drift detection as a SaaS |
This article focuses on the bolded names: Atlas, Bytebase, Skeema, Liquibase, Flyway, Prisma Migrate, Drizzle Kit, and the online DDL tools.
Why these
- Atlas — the fastest-growing tool of 2024-2026. HCL DSL plus a single Go binary plus Schema Monitoring, bundled. Often described as doing for databases what Terraform did for infrastructure.
- Bytebase — the de facto standard for review workflows, approvals, and multi-DB. The AI assistant (SQL review, NL-to-SQL) landed in 2025.
- Skeema — the declarative tool for MySQL. Light and fast. Postgres support went GA in 2025.
- Liquibase — XML, YAML, JSON, and SQL all supported. Explicit change logs and rollback SQL. The de facto standard in enterprise and banking.
- Flyway — the aesthetic of simplicity. Number-stamped SQL files and you are done. Polyglot support widened from 2025.
- Prisma Migrate and Drizzle Kit — bundled with their ORMs. The smoothest integration available.
- gh-ost, pt-osc, pg-osc — they do what the above cannot. Zero-downtime DDL on large live tables.
2. Declarative vs Imperative — The Biggest Branch
This is the first decision. What you write differs.
Declarative (schema-as-code)
You write the desired state. The tool compares it with the current DB, computes the diff, and runs the matching DDL.
# Atlas: schema.hcl — the desired state
table "users" {
schema = schema.public
column "id" { type = bigint, null = false }
column "email" { type = varchar(255), null = false }
column "name" { type = varchar(100), null = true }
primary_key { columns = [column.id] }
index "users_email_uniq" {
unique = true
columns = [column.email]
}
}
- Pros: the schema is in one place. Code review reviews the schema itself.
- Cons: the auto-diff is not always safe. A human re-reads the generated DDL.
Imperative (migration-files)
You write what to change, one file at a time. Each file runs once and is done.
-- Flyway: V001__add_users_table.sql
CREATE TABLE users (
id BIGINT PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
name VARCHAR(100)
);
-- V002__add_users_created_at.sql
ALTER TABLE users ADD COLUMN created_at TIMESTAMPTZ DEFAULT now();
- Pros: humans know exactly what runs. Rollback SQL can be written separately.
- Cons: to picture the full schema you must mentally merge N files. Conflicts and renames are awkward.
Which is better
Neither dominates. But the 2026 vibe is clear:
- New full-stack teams increasingly start with declarative (Drizzle Kit, Atlas, Prisma
db push). - Enterprises, banks, and regulated shops still favor imperative (Liquibase, Flyway). Explicit rollback SQL and audit trails tie directly to compliance.
- Atlas put both camps in one tool. Declarative via
atlas schema apply, versioned viaatlas migrate diffandatlas migrate apply.
3. Atlas — The Rising Contender
3.1 What is different
Atlas is an open-source DB schema tool from Ariga (Israel). Written in Go, distributed as a single binary, with an HCL DSL and a paired cloud SaaS (Atlas Cloud).
Three core ideas.
- Both declarative and imperative.
atlas schema applyis declarative;atlas migrate diffplusatlas migrate applyis imperative. - Schema Monitoring (added in 2024) — periodically snapshots production and compares it against the code schema to detect drift.
- Schema Lint and Schema Versioning —
atlas migrate lintcatches risky DDL (for example unconditional NOT NULL introduction) before it ships.
3.2 HCL schema
# schema.hcl
schema "public" {
comment = "core application"
}
table "users" {
schema = schema.public
column "id" {
type = bigint
null = false
}
column "email" {
type = varchar(255)
null = false
}
column "created_at" {
type = timestamptz
null = false
default = sql("now()")
}
primary_key {
columns = [column.id]
}
index "users_email_uniq" {
unique = true
columns = [column.email]
}
}
One line — atlas schema apply --url "postgres://..." --to "file://schema.hcl" — brings the live DB to this state. Preview with atlas schema diff.
3.3 Schema Monitoring — a new category
Atlas Cloud's biggest differentiator is automated drift detection. When someone runs ALTER TABLE directly in production, or a hotfix migration lands in staging but not production, the tool tells you.
# Periodically snapshot production
atlas schema monitor \
--url "postgres://prod.../app" \
--token "$ATLAS_TOKEN" \
--interval 1h
Drift triggers a Slack or email alert. Flyway, Liquibase, and Prisma Migrate do not offer this category.
3.4 Versioned Migrations + Lint
If you prefer the imperative workflow, use Atlas's versioned mode.
# 1) Compare schema.hcl with current migration history, generate the next SQL file
atlas migrate diff add_user_table \
--dir "file://migrations" \
--to "file://schema.hcl" \
--dev-url "docker://postgres/16/dev"
# 2) Lint the generated migration for risky DDL
atlas migrate lint --dir "file://migrations" --latest 1
# 3) Apply
atlas migrate apply --dir "file://migrations" --url "$DB_URL"
atlas migrate lint catches patterns like:
- Unconditional
NOT NULLintroduction on large tables (lock risk). - Long-held locks during index creation (
CREATE INDEXwithoutCONCURRENTLY). - Data-loss risks (column drop, type narrowing).
3.5 Who should pick Atlas
- Teams comfortable with HCL or Terraform and the infra-as-code mental model.
- Multi-DB (Postgres, MySQL, MariaDB, SQLite, MS SQL, partial ClickHouse) in one tool.
- Multi-env or multi-instance teams that need drift detection.
- Teams that want the schema source of truth in code, decoupled from any ORM.
4. Bytebase — Review Workflow as a First-Class Citizen
4.1 What is different
Bytebase is an open-source plus commercial company out of China. Where other tools center on the CLI, Bytebase centers on a GUI plus approval workflow.
Developer -> Change proposal (PR-like Issue) -> SQL Review (auto + human)
-> DBA approval -> Staged env apply (dev -> staging -> prod)
-> Auto backup and rollback scripts preserved
- Multi-DB: MySQL, Postgres, TiDB, Snowflake, MongoDB, ClickHouse, SQL Server, Oracle, Spanner — over 25 engines.
- GitOps mode: triggered by GitHub/GitLab PR merges.
- Automated SQL review: rule-based (column naming, indexing, length limits) plus LLM-based from 2025 onward.
4.2 AI assistant (2025-2026)
Added in Bytebase 3.x.
- NL to SQL: "Show me weekly signups by day" gets translated into SQL.
- SQL Review: an LLM flags risky patterns (un-indexed joins, full scans, lock risks) faster than humans.
- Change impact analysis: estimates which queries, views, and app code the migration affects.
Competing tools have not caught up here. Atlas is adding its own AI, but Bytebase is the most mature.
4.3 Who should pick Bytebase
- Large orgs running multiple DBs and environments with multiple teams.
- Shops where DBAs formally approve and review (finance, healthcare).
- Places where non-developer GUI access (for data analysts and similar) matters.
- Anywhere "who merged this migration PR" needs an audit trail.
Who should not: a single developer or a tiny team. It is overkill. Drizzle Kit plus Atlas migrate is enough.
5. Skeema — Lightweight Declarative for MySQL
Skeema is the embodiment of simplicity. It started as a MySQL tool; Postgres went GA in 2025.
schemas/
- app/
- users.sql # CREATE TABLE users (...)
- posts.sql
- .skeema # connection info
You write the CREATE TABLE statement as-is in *.sql files. skeema diff and skeema push sync with the DB.
- Pros: nothing new to learn. SQL as-is. Fast. CI-friendly.
- Cons: Postgres support is less rich than Atlas. Some objects (enum, partial index, function, trigger) have gaps.
If you run MySQL and want something light, this is the first candidate. The learning curve over Atlas is close to zero.
6. Liquibase — The Sustainable Enterprise Pick
6.1 What is different
Liquibase has been around since 2006. A Java-world standard that is widely used outside Java apps too.
Core concept: the ChangeSet. One change is one ChangeSet, each with an explicit id, author, and rollback SQL.
# changelog.yaml
databaseChangeLog:
- changeSet:
id: 001-create-users
author: alice
changes:
- createTable:
tableName: users
columns:
- column: { name: id, type: BIGINT, constraints: { primaryKey: true } }
- column: { name: email, type: VARCHAR(255), constraints: { nullable: false, unique: true } }
- column: { name: name, type: VARCHAR(100) }
rollback:
- dropTable: { tableName: users }
liquibase update applies, liquibase rollback reverses. Explicit rollback SQL is the big differentiator.
6.2 Changes in 2025-2026
- Liquibase 5.x (2025): faster changelog parsing, new reporting CLI.
- Liquibase AI Advisor: LLM-based review in Liquibase Hub. Similar direction to Atlas Lint and Bytebase Review.
- Wider Postgres extension support: pg_partman, TimescaleDB, pgvector, and friends now have first-class change types.
6.3 Who should pick Liquibase
- Java or Kotlin backends with Spring Boot.
spring-boot-starter-liquibaseis one line. - Enterprise, banking, healthcare — explicit rollback and audit trail map to compliance.
- Multi-DB including Oracle and DB2 — broader engine support than Atlas or Bytebase here.
- Teams that prefer their change log in XML or YAML.
Weakness: XML and YAML are verbose compared to plain SQL. Heavier than Drizzle Kit or Atlas for new teams.
7. Flyway — The Aesthetic of Simplicity
Flyway is even simpler. Version the file by name, write the SQL as-is.
db/migration/
- V1__create_users.sql
- V2__add_users_created_at.sql
- V3__add_users_email_index.sql
-- V2__add_users_created_at.sql
ALTER TABLE users ADD COLUMN created_at TIMESTAMPTZ DEFAULT now();
flyway migrate applies. Rollback is a separate U2__... down file or a new forward migration.
7.1 Changes in 2025-2026
- Flyway 11.x (late 2025): native compiled CLI (GraalVM), faster startup.
- Wider polyglot support: official Docker images and CI guides for Node and Python.
- Flyway Teams/Enterprise features: dry-run for large migrations, automated undo.
7.2 Who should pick Flyway
- Java and Spring Boot default.
spring-boot-starter-flywayis one line. - Teams that want "SQL as-is, the tool stays out of the way".
- Simple single-DB shops (typically Postgres or MySQL).
Weakness: rollback is not a first-class citizen in the Community edition. Liquibase is stronger for complex change tracking.
8. Prisma Migrate and Drizzle Kit — Bundled with the ORM
8.1 Prisma Migrate
schema.prisma (declarative) plus prisma migrate (versioned).
// schema.prisma
model User {
id Int @id @default(autoincrement())
email String @unique @db.VarChar(255)
name String? @db.VarChar(100)
createdAt DateTime @default(now()) @map("created_at")
@@map("users")
}
# Create and apply a new migration (dev)
npx prisma migrate dev --name add_user_table
# Apply in production
npx prisma migrate deploy
- Pros: the ORM model is the schema. One place to look. Shadow DB makes diff generation safer.
- Cons: complex objects (partial index, exclusion constraint, some generated columns, custom domain) cannot be expressed as a Prisma model — you hand-edit the generated
migration.sql.
8.2 Drizzle Kit
// schema.ts (Drizzle schema)
import { pgTable, bigserial, varchar, timestamp, uniqueIndex } from 'drizzle-orm/pg-core'
export const users = pgTable('users', {
id: bigserial('id', { mode: 'bigint' }).primaryKey(),
email: varchar('email', { length: 255 }).notNull(),
name: varchar('name', { length: 100 }),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
}, (t) => ({
emailUniq: uniqueIndex('users_email_uniq').on(t.email),
}))
# Compare schema and DB, generate SQL
npx drizzle-kit generate
# Apply
npx drizzle-kit migrate
- Pros: a light CLI decoupled from the ORM. Generated SQL is conservative and readable.
- Cons: auto-diff is not perfect — column renames need human correction. Edge cases (enum changes, composite PK changes) bite.
8.3 ORM migrations vs Atlas/Liquibase
- ORM tools are the smoothest — model and schema in one place.
- But when the DB uses many objects outside the ORM's view (extensions, materialized views, custom functions), ORM-only migrations fall short.
- A common 2026 pattern: keep the ORM only for read/write types, and run schema separately with Atlas or Liquibase.
9. Online DDL — Zero-Downtime on Large Tables
The above tools share an assumption: the DB executes ALTER TABLE directly. Fine on small tables. But adding a column to a 100M-row table? Most DDL takes a metadata lock. MySQL 8.0 made many DDL operations online, but some still risk locks. Postgres 12+ improved a lot, yet certain changes still take ACCESS EXCLUSIVE.
So online DDL tools are needed.
9.1 gh-ost (MySQL)
GitHub's tool. It avoids triggers and reads the binlog instead. Low overhead.
gh-ost \
--user=admin --password=*** --host=mysql.prod \
--database=app --table=users \
--alter="ADD COLUMN status VARCHAR(20) DEFAULT 'active'" \
--max-load=Threads_running=25 \
--critical-load=Threads_running=1000 \
--chunk-size=2000 \
--execute
How it works: build a shadow table, copy in chunks, follow binlog for missed changes, cut over with a short lock.
9.2 pt-online-schema-change (MySQL)
Part of Percona Toolkit. Older than gh-ost and trigger-based.
pt-online-schema-change \
--alter="ADD COLUMN status VARCHAR(20) DEFAULT 'active'" \
--execute \
D=app,t=users,h=mysql.prod
Pros: battle-tested across more environments. Cons: triggers fire on every INSERT, UPDATE, and DELETE, adding overhead.
9.3 pg-online-schema-change (Postgres)
A relative newcomer. Adapts the shadow-table-plus-trigger-plus-cutover pattern to Postgres. Tools like pg-osc, pg_squeeze, and pg_repack exist (some originally built by Shopify, Stripe, and others) and adoption is growing.
pg-osc run \
--dbname=app --table=users \
--alter="ADD COLUMN status TEXT DEFAULT 'active'" \
--copy-batch-size=10000
Postgres itself handles ALTER TABLE ... ADD COLUMN (with default) quickly since 12, but type changes, NOT NULL introduction, and index rebuilds still benefit from these tools.
9.4 Atlas/Bytebase + online DDL
Integration is just beginning.
- Atlas:
migrate lintwarns on large-table changes. Execution still happens via external tools. - Bytebase: enterprise mode auto-routes some changes through gh-ost.
- Most teams still follow the pattern: 'Have Atlas/Liquibase generate the SQL, but for big tables run it through gh-ost manually'.
10. Real Scenarios — How Each Tool Handles Them
The same change shows the differences clearly. Three scenarios.
10.1 Scenario A — Add a column (status, default 'active')
Flyway
-- V012__add_users_status.sql
ALTER TABLE users ADD COLUMN status VARCHAR(20) DEFAULT 'active' NOT NULL;
Liquibase
- changeSet:
id: 012-add-users-status
author: bob
changes:
- addColumn:
tableName: users
columns:
- column:
name: status
type: VARCHAR(20)
defaultValue: 'active'
constraints: { nullable: false }
rollback:
- dropColumn: { tableName: users, columnName: status }
Prisma Migrate — add status String @default("active") to schema.prisma, then prisma migrate dev.
Drizzle Kit — add status: varchar('status', { length: 20 }).default('active').notNull() to schema.ts, then drizzle-kit generate.
Atlas (declarative) — add the column "status" block to schema.hcl, then atlas schema apply.
Atlas (versioned) — same schema.hcl edit, then atlas migrate diff add_status auto-generates the SQL file.
On large tables — Postgres 12+ adds default-valued columns fast, but on pre-MySQL-8.0 or very large tables you run it through gh-ost. Atlas Lint warns ahead of time.
10.2 Scenario B — Introduce NOT NULL after backfill
One of the riskiest patterns. Done wrong, the lock holds for too long.
Safe order (a variant of expand-contract):
- The column already exists and is nullable. Run a batched backfill (
UPDATE ... WHERE id BETWEEN ... AND ...). - Change the application code to stop writing NULL and deploy.
- Add the
NOT NULLconstraint — on Postgres 12+, useNOT VALIDplusVALIDATE CONSTRAINTto minimize lock time.
Flyway — write steps 1, 2, 3 as separate V files.
Liquibase — addNotNullConstraint. Backfill goes into a sql change or a separate ChangeSet.
Atlas — change null = true to null = false in schema.hcl. atlas migrate lint warns if data is present (unsafe DDL).
Prisma/Drizzle Kit — auto-diff produces only ALTER TABLE ... ALTER COLUMN ... SET NOT NULL. A human must add a backfill migration for safety.
Bytebase — automated SQL review catches "introducing NOT NULL without a backfill" (when the rule is enabled).
10.3 Scenario C — Rename a column (name to display_name)
The most annoying pattern. Auto-diff tools struggle — they see drop plus add.
Common safe order across all tools (rolling rename):
- Add
display_name. Use a trigger or dual-write to keepnameanddisplay_namein sync. - Change the application to read and write only
display_name, then deploy. - Much later, drop the
namecolumn.
Flyway/Liquibase — write all three steps explicitly.
Atlas (declarative) — renaming the column in schema.hcl is interpreted as drop plus add by default. You must give a rename hint explicitly:
column "display_name" {
type = varchar(100)
null = true
comment = "renamed from name"
}
# And pass a hint like --rename old_to_new during atlas migrate diff
Prisma/Drizzle — auto-diff produces drop plus add. Data-loss risk. Hand-edit the migration SQL to use ALTER TABLE ... RENAME COLUMN. Keep the code-side name via @map or varchar('display_name') mapping.
Lesson: never trust auto-diff 100% for renames. A human must verify.
11. Seven-Axis Comparison — At a Glance
11.1 Declarative vs imperative
| Tool | Declarative | Imperative |
|---|---|---|
| Atlas | Yes (schema apply) | Yes (migrate diff/apply) |
| Skeema | Yes | No |
| Drizzle Kit | Yes (schema) | Yes (generated SQL) |
| Prisma Migrate | Yes (db push, dev) | Yes (migrate deploy) |
| Liquibase | No | Yes |
| Flyway | No | Yes |
| Bytebase | Partial | Yes |
11.2 Multi-DB support
| Tool | Postgres | MySQL | SQLite | Oracle | SQL Server | Other |
|---|---|---|---|---|---|---|
| Atlas | Yes | Yes | Yes | Partial | Yes | Partial ClickHouse |
| Bytebase | Yes | Yes | Yes | Yes | Yes | 25+ engines |
| Liquibase | Yes | Yes | Yes | Yes | Yes | DB2, Snowflake, etc. |
| Flyway | Yes | Yes | Yes | Yes | Yes | Many |
| Skeema | Yes | Yes | No | No | No | - |
| Prisma | Yes | Yes | Yes | No | Yes | MongoDB (limited) |
| Drizzle | Yes | Yes | Yes | No | No | D1, LibSQL, others |
11.3 Review workflow
| Tool | Built-in review | Auto lint | LLM review |
|---|---|---|---|
| Bytebase | Yes (GUI) | Yes | Yes |
| Atlas Cloud | Yes | Yes | Partial |
| Liquibase Hub | Yes | Yes | Yes (Advisor) |
| Flyway Enterprise | Partial | Partial | Adding |
| Others (CLI) | No (use Git PR) | No | No |
11.4 Drift detection
| Tool | Automated drift detection | Notes |
|---|---|---|
| Atlas (Cloud) | Yes | Most mature |
| Bytebase | Yes | In the GUI |
| Liquibase | Partial | History-table-based |
| Flyway | Partial | History-table-based |
| Skeema, Prisma, Drizzle | Limited | Only at tool-run time |
11.5 AI assistance (2026)
| Tool | AI features |
|---|---|
| Bytebase | NL to SQL, SQL Review, change impact analysis |
| Atlas | Migrate lint plus some AI suggestions |
| Liquibase | Hub Advisor (LLM review) |
| Others | Rely on external tools (Copilot, Cursor) |
11.6 Online DDL integration
| Tool | Native support | Safe lint | gh-ost routing |
|---|---|---|---|
| gh-ost, pt-osc, pg-osc | (the tool itself) | - | - |
| Atlas | No | Yes (Lint) | No (manual) |
| Bytebase Enterprise | Partial | Yes | Yes |
| Liquibase | No | Partial | No |
| Others | No | No | No |
11.7 ORM integration smoothness
| Tool | TypeScript ORMs | Java/Kotlin | Python | Go |
|---|---|---|---|---|
| Prisma Migrate | Best (own) | - | - | - |
| Drizzle Kit | Best (own) | - | - | - |
| Atlas | Good (Atlas + ORM) | Good (Atlas + JPA) | Good (Atlas + SQLAlchemy) | Best (Atlas's native ecosystem) |
| Liquibase | OK | Best (Spring) | Good | OK |
| Flyway | OK | Best (Spring) | Good | OK |
| Skeema | OK | OK | OK | OK |
12. Per-Team Decision Framework
The first decision is not which tool wins; it is what the team looks like.
12.1 One to three full-stack engineers (TS/Next.js)
- Prisma Migrate or Drizzle Kit alone is enough.
- ORM plus migration bundled means minimal learning and operations cost.
- If Prisma's shadow-DB dev workflow is annoying, pick Drizzle Kit.
- Safety net — add Atlas Cloud's free tier for drift detection only.
12.2 Ten to thirty engineers, TS-heavy (startup)
- Drizzle Kit plus Atlas (lint + drift) is increasingly common.
- Bytebase is still overkill.
- GitOps: the PR carries the SQL output of
drizzle-kit generate, CI runsatlas migrate lint.
12.3 Fifty plus engineers, multi-DB, multi-service (mid-stage startup)
- Bytebase plus Atlas, or Bytebase plus Liquibase.
- The stage where multi-DB support and approval workflows are necessary.
- DBA or platform team is the formal migration gatekeeper.
12.4 Java/Spring Boot enterprise
- Flyway (for simpler changes) or Liquibase (when rollback and audit matter).
- Many shops also layer Atlas or Bytebase on top for multi-DB and drift detection.
12.5 Large tables are critical (1B plus rows)
- Whichever migration tool you use, route large-table changes through gh-ost, pt-osc, or pg-osc.
- Bytebase Enterprise can auto-route; otherwise run manually.
- The migration tool's lint or dry-run should warn on large-table changes ahead of time.
12.6 Multi-cloud, multi-DB engine (Postgres + MySQL + Snowflake, etc.)
- Bytebase or Liquibase — the broadest engine coverage.
- Atlas supports many engines too, but Liquibase is more mature on Oracle, DB2, and Snowflake.
13. Anti-Checklist
Patterns to avoid.
- Running two migration tools against the same DB at once —
_prisma_migrationsandflyway_schema_historycoexist. Two sources of truth. - Trusting auto-diff 100% — column renames are seen as drop plus add. Always have a human review.
- Destructive change without rollback — merging a
DROP COLUMNright before production and "restoring from backup if it breaks"? Not acceptable. Use expand-contract. - Unconditional DDL on big tables — the lock holds too long. Backfill plus
NOT VALIDbefore NOT NULL. - Production without drift detection — finding out someone hand-ran an
ALTER TABLEa year later is too late. - CI without migration lint —
atlas migrate lintor equivalent. Human review is not infallible. - Letting schemas drift across dev/staging/prod — a hotfix in one env only. The next migration may break unpredictably.
14. A Reference Workflow (Illustrative)
One recommended workflow for a small TS-stack team.
- Schema lives in Drizzle code (or Prisma schema). Bundled with the ORM.
- Generate migration SQL automatically and review by humans. The SQL files produced by
drizzle-kit generateorprisma migrate devgo into the PR. atlas migrate lintor similar runs in CI — risky DDL is blocked early.- Production runs
migrate deploy(Prisma) ordrizzle-kit migrate, using a shadow DB. - Atlas Cloud (or equivalent) handles drift detection — catches hand-applied ALTER statements.
- Big-table changes are routed through gh-ost or pg-osc — leave a placeholder in the migration file, execute the actual change via an external tool per the runbook.
- Expand-contract is mandatory — destructive changes never ship in one PR.
For enterprises, add the Bytebase approval gate on top. In the Java world, Liquibase replaces steps 1 and 2.
Epilogue — The Tool is an Expression of Policy, Not Policy Itself
Picking a DB migration tool is not a religious war between declarative and imperative. It is a function of what the team is trying to protect.
- Small team, fast iteration — declarative plus ORM integration (Drizzle Kit, Prisma, Atlas).
- Enterprise plus audit — imperative plus explicit rollback (Liquibase, Flyway).
- Multi-DB and multi-team — review workflow (Bytebase) plus lint (Atlas).
- Big tables — pair the migration tool with online DDL (gh-ost, pg-osc).
The two biggest shifts in May 2026 are:
- Atlas's rise. A single tool that bundles declarative, lint, and drift detection has been gaining share fast. Saying "it does for databases what Terraform did for infrastructure" is not hyperbole.
- AI assistance is now a category. Bytebase, Liquibase Hub, and Atlas all ship LLM-based review or NL translation. Migration lint is no longer purely rule-based.
Decision checklist
- Team size? — One to three: ORM migration. Fifty plus: Bytebase.
- Multi-DB or multi-env? — Yes: Atlas, Bytebase, Liquibase.
- Java/Spring heavy? — Yes: Flyway or Liquibase.
- Big tables? — Yes: layer in gh-ost or pg-osc.
- Need drift detection? — Yes: Atlas Cloud or Bytebase.
- Compliance and rollback critical? — Yes: Liquibase.
- Minimize learning curve? — The ORM's own migration tool.
Anti-patterns recap
- Trusting auto-diff 100%.
- Two migration tools against one DB.
- Destructive change without rollback.
- Unconditional NOT NULL on big tables.
- CI without migration lint.
- Production without drift detection.
- Letting schemas drift across envs.
Coming next
Candidates: "A month with Atlas — is HCL really better than SQL?", "gh-ost vs pt-online-schema-change — benchmarked on a 100M-row table", "A DB change automation pipeline with Bytebase plus GitHub Actions".
"Schema is a fact; migration is the path that moves the fact. Tools make the path safer — they do not walk it for you."
— DB Migration Tools 2026, fin.
References
- Atlas — Modern DB Migration
- Atlas GitHub — ariga/atlas
- Atlas Schema Monitoring
- Atlas Migrate Lint
- Bytebase Official
- Bytebase GitHub
- Bytebase SQL Review Rules
- Skeema — Declarative MySQL/Postgres schema management
- Skeema GitHub
- Liquibase Official
- Liquibase GitHub
- Flyway Official
- Flyway GitHub
- Prisma Migrate Documentation
- Drizzle Kit Documentation
- gh-ost — GitHub's online schema migration for MySQL
- pt-online-schema-change — Percona Toolkit
- pg-osc — Postgres online schema change
- pg_repack — Reorganize tables in PostgreSQL
- Sqitch — Sane database change management
- dbmate — Database migration tool
- PostgreSQL Wiki — Locking
- GitHub Engineering — gh-ost: triggerless schema changes
현재 단락 (1/415)
Database schema change is one of the riskiest tasks in software. A code deploy is easy to roll back;...