Split View: DB 마이그레이션 도구 2026 — Atlas·Bytebase·Skeema·Liquibase·Flyway·Prisma·Drizzle·gh-ost·pg-osc 심층 비교 (선언형 vs 명령형, 리뷰 워크플로, 온라인 DDL)
DB 마이그레이션 도구 2026 — Atlas·Bytebase·Skeema·Liquibase·Flyway·Prisma·Drizzle·gh-ost·pg-osc 심층 비교 (선언형 vs 명령형, 리뷰 워크플로, 온라인 DDL)
프롤로그 — 마이그레이션 도구는 왜 여전히 어려운가
DB 스키마 변경은 소프트웨어에서 가장 위험한 작업 중 하나다. 코드 배포는 롤백이 쉽지만, ALTER TABLE은 한 번 실행되면 디스크 위의 사실이 된다. 큰 테이블에 잘못 락이 걸리면 서비스가 멈춘다.
그래서 마이그레이션 도구가 존재한다. 하지만 2026년 5월 현재 이 카테고리는 어느 때보다 분열되어 있다.
- Liquibase와 Flyway는 2010년대부터 자바 진영의 사실상 표준이었고, 지금도 엔터프라이즈에서는 디폴트다.
- Prisma Migrate·Drizzle Kit은 TypeScript 앱의 디폴트로 자리 잡았다. ORM과 한 묶음으로 와서 가장 매끄럽다.
- **Atlas (Ariga)**는 HCL 기반 declarative schema-as-code로 급속히 점유율을 늘리고 있다. Schema Monitoring·Schema Lint·Versioned Migrations 모두를 한 도구로.
- Bytebase는 리뷰 워크플로를 1급 시민으로 만들었다. 다중 DB·GitOps·AI 어시스턴트까지.
- Skeema는 MySQL 진영에서 가장 가벼운 declarative 도구로 살아남았고 Postgres도 들어왔다.
- 그리고 살아있는 큰 테이블에는 여전히 gh-ost·pt-online-schema-change·pg-online-schema-change 같은 온라인 DDL 도구가 필요하다.
이 글은 이 도구들을 선언형 vs 명령형, 리뷰 워크플로, 드리프트 감지, 다중 DB, AI 어시스턴스, 온라인 DDL 안전성의 축으로 비교한다. 실전 시나리오 — 칼럼 추가, NOT NULL 도입, 대형 테이블 백필, 롤링 리네임 — 를 각 도구로 풀어보고, 팀별 결정 프레임워크를 제시한다.
이 글은 패턴 가이드가 아니라 도구 비교다. 무중단 expand-contract 패턴 자체는 이미 별도 글에서 다뤘다(
2026-04-15 zero-downtime database migration참고). 여기서는 그 패턴을 어느 도구로 어떻게 굴리는지가 핵심이다.
1장 · 풍경 — 도구 지도
먼저 도구를 분류한다. 한 줄에 다 들어가지 않는다.
| 분류 | 도구 | 한 줄 요약 |
|---|---|---|
| 선언형 schema-as-code | Atlas, Skeema, Drizzle Kit | "있어야 할 상태"를 적으면 diff를 만든다 |
| 명령형 migration-files | Liquibase, Flyway, Prisma Migrate, dbmate, Sqitch | "무엇을 바꿀지" 한 파일씩 직접 적는다 |
| 리뷰 워크플로 중심 | Bytebase, Atlas Cloud | PR·승인·롤백·실행을 한 화면에서 |
| 온라인 DDL (큰 테이블 전용) | gh-ost, pt-online-schema-change, pg-online-schema-change | 쉐도우 테이블 + 트리거 + cutover |
| 클라우드 매니지드 | Atlas Cloud, Bytebase Hub, Liquibase Hub | 실행 로그·승인·드리프트 감지 SaaS |
이 글의 초점은 굵게 표시된 도구들이다. Atlas·Bytebase·Skeema·Liquibase·Flyway·Prisma Migrate·Drizzle Kit, 그리고 온라인 DDL 도구들.
왜 이 도구들인가
- Atlas — 2024~2026 사이 가장 빠르게 자란 도구. HCL DSL + Go 단일 바이너리 + Schema Monitoring이 묶음. Terraform이 인프라에 한 일을 DB에 하고 있다는 평가.
- Bytebase — 리뷰 워크플로·승인·다중 DB의 사실상 표준. 2025년부터 AI 어시스턴트(SQL Review·자연어→SQL)가 합쳐졌다.
- Skeema — MySQL의 declarative 도구. 가볍고 빠르다. 2025년 들어 Postgres 지원 정식 도입.
- Liquibase — XML/YAML/JSON/SQL 모두 지원. 변경 로그·롤백 SQL을 명시적으로 적는 전통. 엔터프라이즈·은행권 사실상 표준.
- Flyway — 단순함의 미학. SQL 파일에 버전 번호 붙이고 끝. 2025년부터 polyglot 지원 확대.
- Prisma Migrate·Drizzle Kit — 각 ORM의 한 식구. 가장 매끄러운 통합.
- gh-ost·pt-osc·pg-osc — 위 도구들이 못 하는 일을 한다. 큰 테이블의 무중단 DDL.
2장 · 선언형 vs 명령형 — 가장 큰 분기점
DB 마이그레이션 도구 선택의 첫 분기점이다. 무엇을 적는가가 다르다.
선언형 (declarative, schema-as-code)
"있어야 할 상태"를 적는다. 도구가 현재 DB와 비교해 diff를 만들고, 그 diff에 해당하는 DDL을 실행한다.
# Atlas: schema.hcl — 있어야 할 상태
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]
}
}
- 장점: 스키마가 한 곳에 모인다. 코드 리뷰가 "스키마 자체"를 본다.
- 단점: 자동 diff가 안전하지 않을 수 있다. 도구가 만든 DDL을 사람이 다시 본다.
명령형 (imperative, migration-files)
"무엇을 바꿀지"를 한 파일씩 적는다. 각 파일은 한 번 실행되면 끝.
-- 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();
- 장점: 무엇이 도는지 사람이 정확히 안다. 롤백 SQL을 별도로 적을 수 있다.
- 단점: 스키마 전체 모양은 N개 파일을 머리로 합쳐야 안다. 충돌 머지·리네임이 어렵다.
어느 쪽이 우월한가
둘 다 우월하지 않다. 다만 2026년의 분위기는 분명하다:
- 신규 풀스택 팀은 선언형으로 시작하는 비율이 늘었다(Drizzle Kit·Atlas·Prisma
db push). - 엔터프라이즈·은행·관리 감독이 있는 곳은 여전히 명령형이 우세하다(Liquibase·Flyway). 감사 추적, 명시적 롤백 SQL이 컴플라이언스에 직결된다.
- Atlas는 두 진영을 한 도구에 넣었다. declarative
atlas schema apply도, versionedatlas migrate apply도 있다.
3장 · Atlas — 부상하는 강자
3.1 무엇이 다른가
Atlas는 이스라엘의 Ariga 사가 만든 오픈 소스 DB 스키마 도구다. Go로 작성됐고, 단일 바이너리, HCL DSL, 그리고 cloud SaaS(Atlas Cloud)가 따라온다.
핵심은 세 가지.
- 선언형과 명령형을 모두 지원한다.
atlas schema apply는 선언형,atlas migrate diff+atlas migrate apply는 명령형. - Schema Monitoring(2024년 도입) — production DB를 주기적으로 스냅숏 뜨고, 코드의 schema와 비교해 드리프트를 감지한다.
- Schema Lint·Schema Versioning —
atlas migrate lint로 위험 DDL(예: 비조건적 NOT NULL 도입)을 사전에 잡는다.
3.2 HCL 스키마
# 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]
}
}
atlas schema apply --url "postgres://..." --to "file://schema.hcl" 한 줄로 현재 DB를 이 상태로 맞춘다. 미리 보고 싶다면 atlas schema diff.
3.3 Schema Monitoring — 새 카테고리
Atlas Cloud의 가장 큰 차별점은 드리프트 감지의 자동화다. 누군가 production에서 직접 ALTER TABLE을 친 사실, 또는 hotfix migration이 staging에는 적용되고 production에는 적용 안 된 사실을 도구가 알려준다.
# 주기적으로 production을 스냅숏
atlas schema monitor \
--url "postgres://prod.../app" \
--token "$ATLAS_TOKEN" \
--interval 1h
드리프트가 있으면 Slack·이메일로 알림. 이건 Flyway·Liquibase·Prisma Migrate에는 없는 카테고리다.
3.4 Versioned Migrations + Lint
명령형 워크플로를 선호한다면 Atlas의 versioned mode를 쓴다.
# 1) 코드의 schema.hcl과 현재 migration history를 비교해 새 SQL 파일 생성
atlas migrate diff add_user_table \
--dir "file://migrations" \
--to "file://schema.hcl" \
--dev-url "docker://postgres/16/dev"
# 2) 위험 DDL이 있는지 lint
atlas migrate lint --dir "file://migrations" --latest 1
# 3) 적용
atlas migrate apply --dir "file://migrations" --url "$DB_URL"
atlas migrate lint는 다음 같은 패턴을 잡는다.
- 큰 테이블에 비조건적
NOT NULL도입 (락 위험). - 락을 길게 유지하는 인덱스 생성 (
CREATE INDEX비-CONCURRENTLY). - 데이터 손실 위험 변경 (column drop, type narrowing).
3.5 누가 Atlas를 쓰면 좋은가
- HCL/Terraform 친화적이고, infra-as-code 멘탈 모델에 익숙한 팀.
- 다중 DB(Postgres, MySQL, MariaDB, SQLite, MS SQL, ClickHouse 일부) 한 도구로.
- 드리프트 감지가 필요한 멀티 환경(staging·prod)·멀티 인스턴스 팀.
- ORM과 무관하게 DB 진실의 원천을 코드에 두고 싶은 팀.
4장 · Bytebase — 리뷰 워크플로 1급 시민
4.1 무엇이 다른가
Bytebase는 중국 출신의 오픈 소스 + 상용 회사. 다른 도구들이 CLI를 중심에 두는 반면, Bytebase는 GUI + 승인 워크플로를 중심에 둔다.
개발자 → 변경 제안(PR-like Issue) → SQL Review(자동·사람)
→ DBA 승인 → 단계적 환경 적용(dev → staging → prod)
→ 자동 백업·롤백 스크립트 보존
- 다중 DB: MySQL·Postgres·TiDB·Snowflake·MongoDB·ClickHouse·SQL Server·Oracle·Spanner 등 25종 이상.
- GitOps 모드: GitHub/GitLab PR 머지로 트리거.
- 자동 SQL Review: 룰 기반(컬럼 명명·인덱스·길이 제한 등) + 2025년부터 LLM 기반.
4.2 AI 어시스턴트 (2025~2026)
Bytebase 3.x부터 추가된 기능.
- 자연어 → SQL: "지난주 가입자 일별로 보여줘" 같은 요청을 SQL로.
- SQL Review: LLM이 위험 패턴(인덱스 없는 join, full scan, 락 위험)을 사람보다 빠르게 잡는다.
- 변경 영향 분석: 이 마이그레이션이 영향 주는 쿼리·뷰·앱 코드 추정.
이 카테고리는 다른 도구들이 아직 깊게 못 따라왔다. Atlas도 자체 AI를 붙이고는 있지만 Bytebase가 가장 성숙하다.
4.3 누가 Bytebase를 쓰면 좋은가
- 다중 DB·다중 환경·여러 팀이 같이 쓰는 큰 조직.
- DBA가 정식으로 승인·리뷰하는 프로세스가 필요한 곳(금융·헬스케어).
- GUI를 통한 비-개발자 접근(데이터 분석가 등)이 필요한 곳.
- "마이그레이션 PR을 누가 머지했는가"를 감사 추적해야 하는 곳.
누가 쓰지 말 것: 1인 또는 소규모 팀. 오버킬이다. Drizzle Kit + Atlas migrate가 충분.
5장 · Skeema — MySQL 진영의 가벼운 declarative
Skeema는 단순함의 화신이다. MySQL용으로 시작했고 2025년에 Postgres 정식 지원.
schemas/
├─ app/
│ ├─ users.sql # CREATE TABLE users (...)
│ ├─ posts.sql
│ └─ .skeema # connection info
*.sql 파일에 CREATE TABLE 문 그대로 적는다. skeema diff·skeema push로 DB와 동기화.
- 장점: 다른 도구를 안 배워도 된다. SQL을 그대로 적는다. 빠르다. CI 친화적.
- 단점: Postgres 지원이 Atlas만큼 풍부하진 않다. enum·partial index·function·trigger 등 일부 객체 지원에 격차.
MySQL을 쓰면서 가벼운 도구를 원하면 가장 먼저 검토할 후보. Atlas와 비교해 학습 곡선이 거의 0이다.
6장 · Liquibase — 엔터프라이즈의 지속 가능한 선택
6.1 무엇이 다른가
Liquibase는 2006년부터 있다. 자바 진영의 표준이지만 자바 앱이 아닌 곳에서도 잘 쓰인다.
핵심 개념: ChangeSet. 변경 하나가 하나의 ChangeSet이고, 각각이 id·author·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로 적용, liquibase rollback으로 되돌림. 명시적인 rollback SQL이 큰 차이점이다.
6.2 2025~2026의 변화
- Liquibase 5.x(2025): 더 빠른 changelog 파싱, 새 reporting CLI.
- Liquibase AI Advisor: Liquibase Hub에서 LLM 기반 리뷰. Atlas Lint·Bytebase Review와 비슷한 방향.
- PostgreSQL extension 지원 확대: pg_partman·TimescaleDB·pgvector 등 익스텐션 친화 변경 지원.
6.3 누가 Liquibase를 쓰면 좋은가
- 자바·코틀린 백엔드 + Spring Boot.
spring-boot-starter-liquibase한 줄. - 엔터프라이즈·은행·헬스케어 — 명시적 rollback과 감사 추적이 컴플라이언스 요건.
- 멀티 DB(Oracle·DB2 포함) — Atlas·Bytebase보다 Oracle·DB2 친화도가 높음.
- 변경 로그를 XML/YAML로 가지고 싶은 팀.
약점: XML/YAML은 SQL을 직접 쓸 때보다 장황하다. Drizzle Kit·Atlas와 비교해 신규 팀에는 무거울 수 있다.
7장 · Flyway — 단순함의 미학
Flyway는 더 단순하다. 파일 이름으로 버전을 매기고, SQL을 그대로 적는다.
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로 적용. rollback은 별도 down 파일(U2__...) 또는 새 forward migration으로 푼다.
7.1 2025~2026 변화
- Flyway 11.x(2025년 후반): Native compiled CLI(GraalVM), 더 빠른 startup.
- Polyglot 친화 확대: Node/Python 진영을 위한 공식 도커 이미지 정리·CI 가이드.
- Flyway Teams/Enterprise의 새 features: 대규모 마이그레이션 dry-run, undo 자동화.
7.2 누가 Flyway를 쓰면 좋은가
- 자바·Spring Boot의 디폴트.
spring-boot-starter-flyway한 줄. - "SQL 그대로, 도구는 가볍게" 원하는 팀.
- 단순한 단일 DB(주로 Postgres·MySQL) 운영.
약점: rollback이 1급 시민이 아니다(community edition). 복잡한 변경에는 Liquibase가 더 강하다.
8장 · Prisma Migrate · Drizzle Kit — ORM과 한 묶음
8.1 Prisma Migrate
schema.prisma(declarative)와 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")
}
# 새 마이그레이션 생성 + 적용 (개발용)
npx prisma migrate dev --name add_user_table
# 프로덕션 적용
npx prisma migrate deploy
- 장점: ORM의 모델 정의가 곧 스키마. 한 곳에서 본다. 셰도우 DB로 안전한 diff 생성.
- 단점: 복잡한 객체(partial index, exclusion constraint, generated column 일부, custom domain)는 Prisma 모델로 표현 못 함 —
migration.sql을 직접 편집해야 함.
8.2 Drizzle Kit
// schema.ts (드리즐 스키마)
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),
}))
# 스키마와 DB를 비교해 SQL 파일 생성
npx drizzle-kit generate
# 적용
npx drizzle-kit migrate
- 장점: ORM과 분리된 가벼운 CLI. SQL 파일이 보수적이고 읽기 쉽다.
- 단점: 자동 diff가 100%는 아님 — 컬럼 리네임 등은 사람 보정 필요. 일부 객체(enum 변화, 복합 PK 변경) 가장자리.
8.3 ORM 마이그레이션 vs Atlas/Liquibase
- ORM 도구가 가장 매끄럽다 — 모델과 스키마가 한 곳.
- 그러나 DB가 ORM의 시야 밖 객체(extension, materialized view, custom function)를 많이 쓰면 ORM 마이그레이션만으로 부족.
- 그런 팀은 ORM은 read/write 타입용으로만 쓰고, 스키마는 Atlas/Liquibase로 따로 운영하는 패턴이 늘었다.
9장 · 온라인 DDL — 큰 테이블의 무중단
위 도구들의 공통점: DB가 직접 ALTER TABLE을 실행한다는 가정. 작은 테이블이면 문제없다. 그러나 1억 row 테이블에 새 컬럼을 추가하면? 대부분의 DDL이 메타데이터 락을 잡는다. MySQL은 8.0 이후 많은 DDL이 online이지만, 여전히 락 위험이 있는 변경이 있다. Postgres는 12+ 이후 많이 좋아졌지만 일부 변경은 여전히 ACCESS EXCLUSIVE 락.
그래서 온라인 DDL 도구가 필요하다.
9.1 gh-ost (MySQL)
GitHub이 만든 도구. 트리거를 쓰지 않고 binlog만 본다. 부하가 낮다.
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
작동: 쉐도우 테이블 생성 → 청크 단위 복사 → binlog로 누락 변경 따라잡기 → 짧은 락으로 cutover.
9.2 pt-online-schema-change (MySQL)
Percona Toolkit의 일부. gh-ost보다 오래됐고, 트리거 기반이다.
pt-online-schema-change \
--alter="ADD COLUMN status VARCHAR(20) DEFAULT 'active'" \
--execute \
D=app,t=users,h=mysql.prod
장점: 더 오래 검증됐고 더 다양한 환경에서 돈다. 단점: 트리거가 INSERT/UPDATE/DELETE에 매번 따라붙어 부하가 있다.
9.3 pg-online-schema-change (Postgres)
상대적으로 후발 주자. shadow table + 트리거 + cutover 패턴을 Postgres에 맞췄다. Shopify·Stripe 등이 만든 도구들이 있고 (pg-osc·pg_squeeze·pg_repack), 활용도가 늘고 있다.
pg-osc run \
--dbname=app --table=users \
--alter="ADD COLUMN status TEXT DEFAULT 'active'" \
--copy-batch-size=10000
Postgres 자체가 ALTER TABLE ... ADD COLUMN(기본값 있는)을 12+에서 빠르게 처리하긴 하지만, type change·NOT NULL 도입·인덱스 재구성 같은 변경에는 여전히 도움이 된다.
9.4 Atlas/Bytebase + 온라인 DDL
도구 통합이 막 시작됐다.
- Atlas:
migrate lint가 큰 테이블 변경을 경고. 실행은 여전히 외부 도구. - Bytebase: 일부 변경을 자동으로 gh-ost로 라우팅하는 모드(엔터프라이즈).
- 대부분의 팀은 여전히 'Atlas/Liquibase가 만든 SQL을 사람이 보고, 큰 테이블이면 gh-ost로 직접 실행' 패턴.
10장 · 실전 시나리오 — 도구별 풀이
같은 변경을 도구별로 보면 차이가 극명하다. 시나리오 셋.
10.1 시나리오 A — 새 컬럼 추가 (status, 기본값 '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 — schema.prisma에 status String @default("active") 추가 후 prisma migrate dev.
Drizzle Kit — schema.ts에 status: varchar('status', { length: 20 }).default('active').notNull() 추가 후 drizzle-kit generate.
Atlas (declarative) — schema.hcl에 column "status" 블록 추가, atlas schema apply.
Atlas (versioned) — 위와 같이 schema.hcl 수정 후 atlas migrate diff add_status → SQL 파일 자동 생성.
큰 테이블이라면 — Postgres 12+는 기본값 있는 컬럼 추가도 빠르지만, MySQL 8.0 이전이거나 매우 큰 테이블이면 gh-ost로 실행한다. Atlas Lint가 사전 경고.
10.2 시나리오 B — 기존 컬럼에 NOT NULL 도입 (백필 후)
가장 위험한 패턴 중 하나. 잘못하면 락이 길게 걸린다.
안전한 순서 (expand-contract 패턴 변형):
- 컬럼은 이미 있고 nullable. 백필 SQL을 batch로 실행 (
UPDATE ... WHERE id BETWEEN ... AND ...). - application 코드가 더 이상 NULL을 쓰지 않게 수정·배포.
NOT NULLconstraint를 추가 — Postgres 12+에서는NOT VALID+VALIDATE CONSTRAINT패턴으로 락 시간 최소화.
Flyway — 위 1~3을 각각 V-파일로 나누어 적는다.
Liquibase — addNotNullConstraint. 백필은 sql change 또는 별도 ChangeSet.
Atlas — schema.hcl에서 null = true를 null = false로 바꾼다. atlas migrate lint가 데이터가 있다면 경고한다(unsafe DDL).
Prisma/Drizzle Kit — 자동 diff는 ALTER TABLE ... ALTER COLUMN ... SET NOT NULL만 만든다. 백필은 사람이 별도 migration SQL로 추가해야 안전.
Bytebase — 자동 SQL Review가 "백필 없이 NOT NULL을 도입하려고 함"을 잡는다(룰을 켰다면).
10.3 시나리오 C — 컬럼 리네임 (name → display_name)
가장 골치 아픈 패턴. 자동 diff 도구들이 잘 못 잡는다 — drop + add로 인식한다.
모든 도구의 공통 안전한 순서 (롤링 리네임):
display_name추가. 트리거 또는 dual-write로name↔display_name동기화.- application을
display_name만 읽고 쓰게 변경·배포. - 한참 후 —
name컬럼 제거.
Flyway·Liquibase — 위 1~3을 각각 명시적으로 적는다.
Atlas (declarative) — schema.hcl에서 컬럼 이름을 바꾸면 도구는 기본적으로 drop + add로 본다. rename hint를 명시적으로 적어야 함:
column "display_name" {
type = varchar(100)
null = true
comment = "renamed from name"
}
# 그리고 atlas migrate diff 시 --rename old_to_new 같은 힌트 필요
Prisma/Drizzle — 자동으로 drop + add를 만든다. 데이터 손실 위험. 반드시 마이그레이션 SQL을 손으로 수정해 ALTER TABLE ... RENAME COLUMN으로 바꾼다. ORM의 @map/varchar('display_name') 매핑으로 코드 이름은 따로 유지.
교훈: 리네임은 어떤 도구든 자동 diff에 100% 맡기지 않는다. 사람의 확인이 필수.
11장 · 7축 비교 — 한눈에
11.1 선언형 vs 명령형
| 도구 | 선언형 | 명령형 |
|---|---|---|
| Atlas | O (schema apply) | O (migrate diff/apply) |
| Skeema | O | X |
| Drizzle Kit | O (스키마) | O (생성된 SQL) |
| Prisma Migrate | O (db push, dev) | O (migrate deploy) |
| Liquibase | X | O |
| Flyway | X | O |
| Bytebase | 일부 | O |
11.2 다중 DB 지원
| 도구 | Postgres | MySQL | SQLite | Oracle | SQL Server | 기타 |
|---|---|---|---|---|---|---|
| Atlas | O | O | O | 일부 | O | ClickHouse 일부 |
| Bytebase | O | O | O | O | O | 25종 이상 |
| Liquibase | O | O | O | O | O | DB2·Snowflake 등 |
| Flyway | O | O | O | O | O | 다수 |
| Skeema | O | O | X | X | X | - |
| Prisma | O | O | O | X | O | MongoDB 제한 |
| Drizzle | O | O | O | X | X | D1·LibSQL 등 |
11.3 리뷰 워크플로
| 도구 | 빌트인 리뷰 | 자동 lint | LLM 리뷰 |
|---|---|---|---|
| Bytebase | O (GUI) | O | O |
| Atlas Cloud | O | O | 일부 |
| Liquibase Hub | O | O | O (Advisor) |
| Flyway Enterprise | 일부 | 일부 | 도입 중 |
| 나머지 (CLI) | X (Git PR로 대체) | X | X |
11.4 드리프트 감지
| 도구 | 자동 드리프트 감지 | 비고 |
|---|---|---|
| Atlas (Cloud) | O | 가장 성숙 |
| Bytebase | O | GUI에서 |
| Liquibase | 일부 | history table 기반 |
| Flyway | 일부 | history table 기반 |
| Skeema·Prisma·Drizzle | 제한 | 도구 실행 시점에만 |
11.5 AI 어시스턴스 (2026)
| 도구 | AI 기능 |
|---|---|
| Bytebase | 자연어→SQL, SQL Review, 변경 영향 분석 |
| Atlas | Migration lint + 일부 AI 추천 |
| Liquibase | Hub Advisor (LLM 리뷰) |
| 나머지 | 외부 도구(Copilot, Cursor)에 의존 |
11.6 온라인 DDL 통합
| 도구 | 직접 지원 | 안전한 lint | gh-ost 라우팅 |
|---|---|---|---|
| gh-ost·pt-osc·pg-osc | (도구 본인) | - | - |
| Atlas | X | O (Lint) | X (수동) |
| Bytebase Enterprise | 일부 | O | O |
| Liquibase | X | 일부 | X |
| 나머지 | X | X | X |
11.7 ORM 통합 매끄러움
| 도구 | TypeScript ORM | Java/Kotlin | Python | Go |
|---|---|---|---|---|
| Prisma Migrate | 최고(자체) | - | - | - |
| Drizzle Kit | 최고(자체) | - | - | - |
| Atlas | 좋음(Atlas + ORM) | 좋음(Atlas + JPA) | 좋음(Atlas + SQLAlchemy) | 최고 (Atlas 본가) |
| Liquibase | 보통 | 최고 (Spring) | 좋음 | 보통 |
| Flyway | 보통 | 최고 (Spring) | 좋음 | 보통 |
| Skeema | 보통 | 보통 | 보통 | 보통 |
12장 · 팀별 결정 프레임워크
도구 결정의 첫 번째는 도구의 우월성이 아니라 팀의 모양이다.
12.1 1~3인 풀스택 팀 (TS/Next.js)
- Prisma Migrate 또는 Drizzle Kit 단독으로 충분.
- ORM과 마이그레이션이 한 묶음이라 학습·운영 비용 최소.
- 셰도우 DB가 필요한 Prisma의 dev 워크플로가 부담이면 Drizzle Kit.
- 추가 안전망 — Atlas Cloud free tier로 드리프트 감지만 붙이는 정도.
12.2 10~30인 다중 팀, TS 메인 (스타트업)
- Drizzle Kit + Atlas (lint + 드리프트 감지) 조합이 늘었다.
- Bytebase는 아직 오버킬.
- GitOps 모드: PR에
drizzle-kit generate결과 SQL이 들어가고, CI에서atlas migrate lint.
12.3 50인+ 다중 DB 다중 서비스 (mid-stage 스타트업)
- Bytebase + Atlas 또는 Bytebase + Liquibase.
- 다중 DB 지원·승인 워크플로가 필요한 단계.
- DBA 또는 platform 팀이 정식으로 마이그레이션 게이트키퍼.
12.4 자바·Spring Boot 위주 엔터프라이즈
- Flyway (단순한 변경 위주) 또는 Liquibase (롤백·감사 중요).
- 추가로 Atlas 또는 Bytebase를 멀티 DB·드리프트 감지용으로 얹는 패턴도 늘었다.
12.5 큰 테이블이 핵심 (10억 row+)
- 어떤 마이그레이션 도구를 쓰든, 큰 테이블 변경은 gh-ost·pt-osc·pg-osc로 분리.
- Bytebase Enterprise의 자동 라우팅 또는 수동 실행.
- 마이그레이션 도구는 lint·dry-run에서 큰 테이블 변경을 미리 잡아 경고해야 함.
12.6 멀티 클라우드·멀티 DB 엔진 (Postgres + MySQL + Snowflake 등)
- Bytebase 또는 Liquibase — 가장 폭넓은 엔진 지원.
- Atlas도 멀티 DB 지원이지만 Oracle·DB2·Snowflake 같은 곳은 Liquibase가 더 성숙.
13장 · 안티 체크리스트
피해야 할 패턴들.
- 두 개의 마이그레이션 도구를 한 DB에 동시에 운영 — Prisma Migrate가 만든
_prisma_migrations과 Flyway의flyway_schema_history가 동시에 존재. 진실의 원천이 둘. - 자동 diff를 100% 신뢰 — 컬럼 리네임은 drop + add로 인식된다. 사람이 본다.
- rollback 없이 destructive change —
DROP COLUMN을 production 직전에 머지하고, 문제 생기면 백업에서 복원? 안 된다. expand-contract로 풀어야. - 큰 테이블에 비조건적 DDL — 락이 길게 걸린다.
NOT NULL도입 전 백필 +NOT VALID패턴. - 드리프트를 감지 안 하는 production — 누군가
ALTER TABLE을 직접 친 사실을 1년 뒤에 알면 늦다. - CI에서 마이그레이션 lint 없음 —
atlas migrate lint또는 Liquibase/Bytebase 룰. 사람 리뷰가 만능이 아니다. - dev/staging/prod 사이 스키마 불일치 방치 — 한 환경에서만 hotfix 적용. 다음 마이그레이션이 어디서 깨질지 모름.
14장 · 실전 권장 워크플로 (참고용)
작은 팀, TS 스택을 가정한 한 가지 권장 워크플로.
- 스키마는 Drizzle 코드 (또는 Prisma schema). ORM과 한 묶음.
- 마이그레이션 SQL은 자동 생성 + 사람 리뷰.
drizzle-kit generate또는prisma migrate dev로 생성된 SQL 파일을 PR로. - CI에서
atlas migrate lint또는 비슷한 lint — 위험 DDL 사전 차단. - production은
migrate deploy(Prisma) 또는drizzle-kit migrate. 셰도우 DB 사용. - Atlas Cloud(또는 동등)로 드리프트 감지 — 누가 직접 친 ALTER를 잡는다.
- 큰 테이블 변경은 gh-ost/pg-osc로 분리 — 마이그레이션 파일은 placeholder만 남기고, 실제 변경은 runbook에 적힌 외부 도구로.
- expand-contract 패턴 의무화 — destructive change는 절대 한 PR로 가지 않는다.
엔터프라이즈라면 위에 Bytebase의 승인 게이트가 추가된다. 자바 진영이라면 Liquibase가 1, 2번을 대체한다.
에필로그 — 도구는 정책의 표현이지 정책 자체가 아니다
DB 마이그레이션 도구 선택은 "declarative냐 imperative냐"의 종교 전쟁이 아니다. 팀이 무엇을 보호하려고 하는지의 함수다.
- 작은 팀, 빠른 반복 — declarative·ORM 통합(Drizzle Kit·Prisma·Atlas).
- 엔터프라이즈·감사 — imperative·명시적 rollback(Liquibase·Flyway).
- 다중 DB·다중 팀 — 리뷰 워크플로(Bytebase) + lint(Atlas).
- 큰 테이블 — 마이그레이션 도구와 별도로 온라인 DDL 도구(gh-ost·pg-osc).
2026년 5월의 풍경에서 가장 큰 변화는 두 가지다.
- Atlas의 부상 — declarative + lint + 드리프트 감지를 한 도구로 묶어 점유율을 빠르게 늘리고 있다. Terraform이 인프라에 한 일을 DB에 하고 있다는 평가가 과장은 아니다.
- AI 어시스턴스가 카테고리 — Bytebase·Liquibase Hub·Atlas 모두 LLM 기반 리뷰·자연어 변환을 붙였다. 마이그레이션 lint는 더 이상 룰 기반만이 아니다.
결정 체크리스트
- 팀 규모는? — 1~3인이면 ORM 마이그레이션, 50인+면 Bytebase.
- 멀티 DB·멀티 환경인가? — Yes면 Atlas·Bytebase·Liquibase.
- 자바/스프링 위주인가? — Yes면 Flyway·Liquibase.
- 큰 테이블이 있는가? — Yes면 어떤 도구든 gh-ost·pg-osc 추가.
- 드리프트 감지가 필요한가? — Yes면 Atlas Cloud 또는 Bytebase.
- 컴플라이언스(감사·rollback)가 핵심인가? — Yes면 Liquibase.
- 학습 곡선 최소화? — ORM의 자체 마이그레이션 도구.
안티 패턴 요약
- 자동 diff를 100% 신뢰.
- 한 DB에 두 마이그레이션 도구 공존.
- rollback 없이 destructive change.
- 큰 테이블에 비조건적 NOT NULL.
- CI에서 마이그레이션 lint 없음.
- 드리프트 감지 없는 production.
- 환경 간 스키마 불일치 방치.
다음 글 예고
다음 글 후보: Atlas 한 달 써본 후기 — HCL이 정말 SQL보다 좋은가, gh-ost vs pt-online-schema-change 실측 — 1억 row 테이블에서, Bytebase + GitHub Actions로 만드는 DB 변경 자동화 파이프라인.
"스키마는 사실이고, 마이그레이션은 그 사실을 옮기는 길이다. 도구는 길을 안전하게 만들어 줄 뿐, 길 자체를 대신 걸어주진 않는다."
— DB 마이그레이션 도구 2026, 끝.
참고 / References
- Atlas — Modern DB Migration
- Atlas GitHub — ariga/atlas
- Atlas Schema Monitoring
- Atlas Migrate Lint
- Bytebase 공식
- Bytebase GitHub
- Bytebase SQL Review Rules
- Skeema — Declarative MySQL/Postgres schema management
- Skeema GitHub
- Liquibase 공식
- Liquibase GitHub
- Flyway 공식
- 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
DB Migration Tools 2026 — Atlas, Bytebase, Skeema, Liquibase, Flyway, Prisma, Drizzle, gh-ost, pg-osc Deep Comparison (Declarative vs Imperative, Review Workflow, Online DDL)
Prologue — 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