Workflow DB Migration: Flyway vs Liquibase
Dua tool DB migration saya jalankan paralel 24 bulan di BUMN energy + fintech series-B Jakarta. Flyway untuk Spring Boot stack standard. Liquibase untuk multi-database + complex change set. Verdict per stack + complexity.
TL;DR
- Flyway (Community): SQL-first migration, Spring Boot first-class integration. Default untuk single-database stack.
- Liquibase (Community): XML/YAML/JSON changeset, multi-database support, rollback granular. Cocok untuk legacy + multi-DB.
- Atlas (Ariga): schema-first declarative modern. Watch — ekosistem maturing 2026.
- Pattern enterprise: expand-contract untuk zero-downtime + dual-run validation + audit trail ke SIEM.
- Verdict: Conditional — Flyway default modern, Liquibase untuk multi-DB / complex change set.
Konteks
Saya operate kedua tool paralel 24 bulan (Juni 2024 - Mei 2026) di:
- Fintech series-B Jakarta: Flyway Community untuk 18 service Spring Boot, Postgres-only stack, ~720 migration total dalam 24 bulan
- BUMN energy Jakarta: Hybrid — Liquibase untuk 14 service legacy Oracle (incremental migrate ke Postgres), Flyway untuk 8 service greenfield Postgres. Total ~1.200 changeset Liquibase + ~280 migration Flyway
Pengalaman sebelumnya: Flyway 6 tahun (sejak 4.x era), Liquibase 5 tahun (sejak 3.x), beberapa tooling custom DB migration 2018-2020.
Pricing (Juni 2026)
Flyway
- Community (Open Source): gratis Apache 2.0
- Teams: USD 25/instance/bulan, undo support + dry-run
- Enterprise: USD 60/instance/bulan, hot fix + auth + advanced
- Saya pakai Community: Rp 0/bulan
Liquibase
- Community (Open Source): gratis Apache 2.0
- Pro: USD 5/database/bulan, rollback advanced + reporting
- Hub Pro: USD 15-50/user/bulan + advanced governance
- BUMN saya pakai Pro: 14 database × USD 5 = USD 70/bulan = Rp 1,12 juta/bulan
Atlas (sebagai pembanding)
- Open Source: gratis
- Cloud: USD 99-499/bulan tergantung tier
- Saya eval 6 bulan di fintech: gratis tier
Total tooling cost
| Komponen | Cost/bulan |
|---|---|
| Flyway Community (fintech) | Rp 0 |
| Liquibase Pro (BUMN) | Rp 1,12 juta |
| Atlas Cloud (eval, decommission) | Rp 0 |
| Total | Rp 1,12 juta/bulan |
Tooling cost rendah karena pakai community tier. Worth Liquibase Pro di BUMN: advanced rollback + reporting untuk audit compliance — features nyata bermanfaat di skala enterprise.
SLO + performance (24 bulan)
Flyway
| Metrik | Target | Realisasi |
|---|---|---|
| Migration execution time per deploy | < 60 detik | 18-45 detik typical |
| Failure rate (first attempt) | < 2% | 1,4% |
| Zero-downtime migration rate | > 90% | 92% |
| Audit trail completeness | 100% | 100% |
| Rollback successful rate | > 85% | 87% |
Liquibase
| Metrik | Realisasi |
|---|---|
| Migration execution time per deploy | 25-65 detik typical |
| Failure rate | 2,1% (lebih tinggi karena changeset lebih kompleks) |
| Zero-downtime migration rate | 88% |
| Rollback successful rate | 92% (advanced rollback) |
Liquibase unggul di rollback (advanced feature mendukung), Flyway unggul di execution speed + simplicity.
Capability comparison
| Capability | Flyway | Liquibase |
|---|---|---|
| Migration format | SQL native, Java | XML, YAML, JSON, SQL |
| Migration ordering | versioned filename (V1__, V2__) | changeset ID + author |
| Repeatable migration | ya (R__) | ya (runOnChange) |
| Callbacks | ya (beforeMigrate, afterMigrate, dll) | ya (preconditions) |
| Out-of-order migration | dengan flag | native |
| Rollback | terbatas (Community), advanced (Teams+) | first-class (down changeset) |
| Multi-database engine | ya | ya (lebih matang) |
| Spring Boot integration | first-class | dengan starter |
| Schema validation | ya | ya |
| Dry-run | Teams+ | Pro |
| Documentation | mature | mature |
| Hiring di Indonesia | mudah | sedang |
| Operational complexity | rendah | sedang |
| Audit changeset granularity | per-file | per-changeset (lebih granular) |
Trade-off arsitektural
Pilih Flyway kalau:
- Spring Boot + single-database stack (Postgres atau MySQL)
- SQL-first preference (DBA + engineer sama familiar)
- Learning curve rendah penting
- Tim engineering 5-30 dev
- Tidak butuh advanced rollback / dry-run feature paid
Pilih Liquibase kalau:
- Multi-database engine (Postgres + Oracle paralel)
- Complex change set yang lebih bisa di-rollback
- Audit granular per-changeset wajib
- Investment Liquibase existing
- Tim DBA-led (DBA prefer XML/YAML structure)
Pilih Atlas kalau:
- Greenfield 2026+ dengan schema-first declarative preference
- Mau invest di tooling modern (eval ekosistem)
- Tim familiar Terraform-style state management
Pattern: zero-downtime schema migration
Expand-contract 3-phase
Phase 1: Expand (deploy 1)
Add column nullable, add table baru, add index CONCURRENTLY. Backward compatible.
-- V20260601_001__add_payment_metadata.sql (Flyway)
ALTER TABLE payment ADD COLUMN metadata JSONB;
CREATE INDEX CONCURRENTLY idx_payment_metadata_status ON payment USING GIN ((metadata->'status'));
Deploy code tidak berubah behavior — schema baru ada tapi belum dipakai.
Phase 2: Migrate code (deploy 2-N)
Deploy code yang baca/tulis schema baru. Tetap support legacy schema untuk fallback.
// Old code support
if (payment.getMetadata() == null) {
return legacyHandling(payment);
}
// New code path
return newHandling(payment);
Run 2-4 minggu paralel. Validate metadata populated correctly.
Phase 3: Contract (deploy N+1)
Setelah confident, drop kolom unused, rename, finalisasi.
-- V20260715_001__drop_legacy_status_column.sql
ALTER TABLE payment DROP COLUMN legacy_status;
Edge case yang tetap butuh maintenance window
- Foreign key change kompleks dengan table besar (> 100M row)
- Partition split / merge
- Column type change yang tidak compatible (
VARCHAR(50)→INT) - Drop kolom yang masih dipakai (memang harus contract dulu)
Realisasi saya: 8% migration butuh maintenance window (rata-rata 15-30 menit window jam 1-3 dini hari WIB).
Architecture pipeline
Flyway di Spring Boot
# application.yml
spring:
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: true
baseline-version: 0
out-of-order: false
validate-on-migrate: true
Migration run otomatis di startup. Untuk control: disable di Spring config + run via Flyway CLI di pre-deploy job.
Pattern saya:
# Pre-deploy job (CI/CD)
flyway -url=jdbc:postgresql://primary:5432/db migrate
# Post-validate
flyway -url=jdbc:postgresql://primary:5432/db validate
Migration di pre-deploy = atomic dengan deploy. Kalau migration gagal: skip code deploy.
Liquibase di Spring Boot
spring:
liquibase:
enabled: true
change-log: classpath:db/changelog/db.changelog-master.yaml
contexts: prod
ChangeLog master:
databaseChangeLog:
- include:
file: db/changelog/changes/001-create-payment-table.yaml
- include:
file: db/changelog/changes/002-add-payment-index.yaml
ChangeSet individual:
databaseChangeLog:
- changeSet:
id: 001
author: [email protected]
changes:
- createTable:
tableName: payment
columns:
- column:
name: id
type: uuid
constraints:
primaryKey: true
- column:
name: amount_cents
type: bigint
constraints:
nullable: false
rollback:
- dropTable:
tableName: payment
Liquibase XML lebih verbose tapi rollback explicit per-changeset.
Audit log
Flyway pakai table flyway_schema_history. Saya export ke Splunk:
# Cron: weekly export
psql -c "COPY flyway_schema_history TO STDOUT" | splunk-forward
Liquibase pakai databasechangelog table. Similar pattern export.
Format audit: who deployed, version, timestamp, execution time, success/fail. Compliance OJK 7 tahun retention via Splunk + S3 Glacier.
Common pitfall
- Migration tidak idempotent.
INSERT INTO config (key, value) VALUES (...)tanpaON CONFLICT= fail saat re-run. Pakai upsert atau check existence. - Long-running migration di big table.
ALTER TABLE ... ADD COLUMN ... DEFAULT 'x'di Postgres lock table sampai selesai. Untuk table 100M row = jam-jam downtime. PakaiADD COLUMN NULLlalu backfill batch. - CREATE INDEX tanpa CONCURRENTLY. Postgres
CREATE INDEXlock table. SelaluCREATE INDEX CONCURRENTLYdi production. Tidak bisa dalam transaction — pakai script terpisah. - Migration tidak di-test di staging dengan data realistic. Schema change yang fast di dev (data 1k row) bisa lambat di production (100M row). Test dengan dataset realistic.
- No backup before migration. Migration besar = wajib backup sebelum. PITR Postgres 5 menit RPO + on-demand snapshot pre-migration besar.
Multi-environment workflow
Pattern saya untuk 3 environment (dev, staging, prod):
Developer commit migration → PR
│
├── CI: validate syntax + dry-run di ephemeral DB
├── PR review (mandatory: 1 reviewer untuk dev, 2 untuk staging+)
│
└── Merge ke main
│
├── Auto-deploy ke dev (immediate)
│
├── Auto-promote ke staging setelah 24 jam di dev
│
└── Manual approval gate untuk prod (compliance)
│
└── Deploy ke prod via Argo Rollouts
├── Pre-deploy: backup snapshot
├── Deploy: flyway migrate
├── Post-deploy: smoke test
└── Audit: log ke Splunk
Per-environment approval gate untuk fintech / BUMN: compliance-required.
Migration risk
Flyway → Liquibase (atau sebaliknya)
Tidak common, butuh significant effort untuk re-write semua migration.
- Effort: 6-10 minggu untuk 200+ migration
- Pain point: history table format berbeda, harus seed Liquibase databasechangelog table dari Flyway schema_history
- Worth-nya: hampir tidak pernah. Stay di tool existing.
Manual SQL script → Flyway/Liquibase
Worth migration untuk team yang belum punya tool formal.
- Effort: 2-4 minggu setup + baseline existing schema
- Pattern:
flyway baselineatau Liquibase initial changeset capture existing schema - Outcome: audit trail formal + reproducibility setup environment baru
Cost of ownership 36 bulan
Skenario: fintech 18 service Postgres + BUMN 14 service Oracle/Postgres hybrid.
| Item | Fintech (Flyway Community) | BUMN (Liquibase Pro hybrid) |
|---|---|---|
| Tooling 3 tahun | Rp 0 | Rp 40 juta |
| Ops engineer DB | Rp 120 juta | Rp 180 juta |
| Migration disaster recovery (incident, rollback) | Rp 28 juta | Rp 35 juta |
| Custom tooling (audit exporter, dll) | Rp 25 juta | Rp 60 juta |
| Total 3 tahun | Rp 173 juta | Rp 315 juta |
BUMN cost lebih tinggi karena multi-DB complexity + Liquibase Pro license + custom tooling untuk audit granularity.
Indonesia specific
Compliance OJK
OJK Cyber Resilience mensyaratkan change control untuk database production. Pattern:
- Migration file di Git dengan branch protection
- PR review mandatory + 2 approver untuk prod
- Audit log siapa-deploy-kapan ke Splunk
- Retention audit 7 tahun via S3 Glacier
- Quarterly review migration history dengan auditor internal
KAP audit Q1 2026: 0 finding terkait DB migration. Pattern matang.
Maintenance window
Untuk service payment fintech: maintenance window jam 1-3 WIB (low-traffic period). Untuk BUMN energy customer-facing: maintenance window jam 0-5 WIB (off-business hours).
Plan maintenance window 7-14 hari sebelumnya, notifikasi customer + internal stakeholder.
Hiring
DBA Postgres di Jakarta: pool moderate, kompensasi Rp 25-40 juta/bulan senior. Flyway / Liquibase familiarity umum di tim Spring Boot — tidak butuh hiring spesialis.
DBA Oracle untuk BUMN legacy: pool decreasing 2024+, kompensasi premium Rp 40-65 juta/bulan untuk senior. Faktor untuk plan migrate Oracle → Postgres dalam roadmap 2026-2028.
Yang surprising
Setelah 24 bulan + ~1.000 migration: 1,4% failure rate ternyata acceptable. Saya kira akan lebih rendah (target < 1%) tapi realisasi mostly disebabkan oleh data anomali yang tidak terdeteksi di staging (data production lebih kotor dari ekspektasi). Lesson: tetap pakai dataset realistic di staging, copy snapshot anonymized dari production weekly.
Surprise lain: expand-contract pattern butuh disiplin engineering yang lebih tinggi dari ekspektasi. Engineer junior cenderung shortcut “deploy schema + code bareng” karena lebih cepat — sampai hit production incident. Setelah 2 P1 incident, mandate review wajib + check di CI lint pattern dijalankan formal.
Verdict
Conditional dengan rule konkret:
- Default Spring Boot + Postgres-only stack: Flyway Community. Cost Rp 0 + simplicity wins.
- Multi-database (Oracle legacy + Postgres) atau complex changeset: Liquibase Community atau Pro (kalau audit granularity wajib).
- Greenfield 2026+ stack: Atlas worth eval, monitor maturity.
- Skip migration tool formal kalau tim < 3 dev + 1 database + < 30 migration total. Manual SQL + Git tracking cukup.
Threshold konkret untuk adopt migration tool: 3+ dev + 5+ environment (dev/staging/prod × multiple instance) + 20+ migration total atau growing. Di atas threshold, tooling formal saves time + reduce risk.
Ditulis oleh Asti Larasati