The APAC Database Migration Problem
APAC engineering teams that have adopted CI/CD for application code often maintain a manual exception for database schema changes: the DBA applies schema changes manually before deployment, or migrations run outside the pipeline as a separate operation. The result is deployment coupling — APAC application code and its required schema changes deploy out of sync — and audit gaps where the APAC schema change history exists only in tribal memory.
Three tools address different APAC database migration workflows:
SQL-first, explicit control: Flyway applies numbered SQL migration files sequentially — APAC teams write the exact SQL, Flyway tracks which have been applied. No abstraction between the APAC engineer and the SQL.
Changeset abstraction with compliance audit: Liquibase manages changes through typed changesets (XML, YAML, JSON) with automatic rollback generation and structured audit trails. Appropriate for APAC regulated environments where schema change governance is required.
Declarative schema-as-code: Atlas manages the desired schema state in HCL or SQL definitions, computes diffs against the current APAC database, and generates migration SQL automatically. Follows Terraform-style workflows for APAC platform teams treating databases as infrastructure.
Flyway: Pipeline-Native SQL Migrations for APAC Engineering Teams
The Flyway model: numbered SQL files, sequential execution
apac-service/
├── src/
│ └── ...
└── db/
└── migration/
├── V1__create_apac_schema.sql
├── V2__add_apac_customer_table.sql
├── V3__create_apac_order_indexes.sql
├── V4__add_apac_region_column.sql
└── V5__create_apac_notification_table.sql
Flyway reads these files in version order, compares against the flyway_schema_history table in the APAC target database, and applies any pending migrations — leaving already-applied migrations untouched.
-- V4__add_apac_region_column.sql
-- Safe APAC migration pattern: add nullable column, backfill, add constraint
ALTER TABLE apac_customer_accounts
ADD COLUMN region_code CHAR(2);
UPDATE apac_customer_accounts
SET region_code = CASE
WHEN country_code IN ('SG', 'MY', 'ID', 'PH', 'VN', 'TH') THEN 'SEA'
WHEN country_code IN ('JP', 'KR', 'TW', 'CN', 'HK') THEN 'NEA'
ELSE 'OTHER'
END;
ALTER TABLE apac_customer_accounts
ALTER COLUMN region_code SET NOT NULL;
CREATE INDEX idx_apac_customer_region
ON apac_customer_accounts(region_code, country_code);
Flyway in GitHub Actions for APAC CI/CD
# .github/workflows/apac-deploy.yml
name: APAC Service Deploy
on:
push:
branches: [main]
jobs:
migrate-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run APAC database migrations (Flyway)
uses: joshuaavalon/flyway-action@v3
with:
url: jdbc:postgresql://${{ secrets.APAC_DB_HOST }}:5432/apac_db
user: ${{ secrets.APAC_DB_USER }}
password: ${{ secrets.APAC_DB_PASSWORD }}
locations: filesystem:db/migration
# Fail deploy if APAC schema history checksum mismatch
validateOnMigrate: true
- name: Deploy APAC application container
# Application deploys only after successful APAC migration
run: |
kubectl set image deployment/apac-service \
apac-service=${{ env.IMAGE }}:${{ github.sha }} \
-n apac-production
Flyway Docker for APAC containerized pipelines
# Run APAC Flyway migration from Docker (no local Java required)
docker run --rm \
-v "$(pwd)/db/migration:/flyway/sql" \
flyway/flyway:latest \
-url="jdbc:postgresql://apac-db.internal:5432/apac_db" \
-user="apac_migrator" \
-password="${APAC_DB_PASSWORD}" \
-schemas="apac_core,apac_analytics" \
migrate
# Validate APAC schema history without applying migrations
docker run --rm \
-v "$(pwd)/db/migration:/flyway/sql" \
flyway/flyway:latest \
-url="jdbc:postgresql://apac-db.internal:5432/apac_db" \
-user="apac_migrator" \
-password="${APAC_DB_PASSWORD}" \
validate
# Info: show APAC migration status (pending vs applied)
docker run --rm \
-v "$(pwd)/db/migration:/flyway/sql" \
flyway/flyway:latest \
-url="jdbc:postgresql://apac-db.internal:5432/apac_db" \
-user="apac_migrator" \
-password="${APAC_DB_PASSWORD}" \
info
Flyway configuration for APAC multi-environment deployments
# flyway.conf: APAC environment-specific configuration
# (Override with environment variables: FLYWAY_URL, FLYWAY_USER, etc.)
flyway.url=jdbc:postgresql://apac-db-prod.internal:5432/apac_db
flyway.user=apac_migrator
flyway.schemas=apac_core,apac_analytics
flyway.locations=filesystem:db/migration
flyway.validateOnMigrate=true
flyway.outOfOrder=false # Block APAC out-of-order migrations
flyway.placeholders.apac_env=production
Liquibase: Compliance-Grade Change Management for APAC Enterprise
When APAC teams need changeset audit trails
APAC regulated industries have DBA change management processes that require:
- Every APAC schema change tracked with author, description, and timestamp
- Change rollback plans documented before APAC production deployment
- Change approval workflows integrated with APAC ITSM systems
Liquibase's changelog format provides these natively.
Liquibase YAML changesets for APAC
# db/changelog/apac-changes.yaml
databaseChangeLog:
- changeSet:
id: "2026-04-28-001"
author: "apac-platform-team"
comment: "APAC: Add KYC verification status to customer accounts"
changes:
- addColumn:
tableName: apac_customer_accounts
columns:
- column:
name: kyc_status
type: VARCHAR(20)
defaultValue: "pending"
constraints:
nullable: false
- column:
name: kyc_verified_at
type: TIMESTAMP
- column:
name: kyc_provider
type: VARCHAR(50)
rollback:
- dropColumn:
tableName: apac_customer_accounts
columnName: kyc_status
- dropColumn:
tableName: apac_customer_accounts
columnName: kyc_verified_at
- dropColumn:
tableName: apac_customer_accounts
columnName: kyc_provider
- changeSet:
id: "2026-04-28-002"
author: "apac-data-team"
comment: "APAC: Index for KYC status filtering queries"
changes:
- createIndex:
indexName: idx_apac_customer_kyc_status
tableName: apac_customer_accounts
columns:
- column:
name: kyc_status
- column:
name: kyc_verified_at
rollback:
- dropIndex:
indexName: idx_apac_customer_kyc_status
tableName: apac_customer_accounts
Liquibase diff for APAC schema drift detection
# Compare APAC production database against APAC staging reference schema
liquibase \
--url="jdbc:postgresql://apac-prod.internal:5432/apac_db" \
--referenceUrl="jdbc:postgresql://apac-staging.internal:5432/apac_db" \
--username=apac_migrator \
--password="${APAC_DB_PASSWORD}" \
diff
# Generate APAC changelog from diff (APAC staging → APAC production)
liquibase \
--url="jdbc:postgresql://apac-prod.internal:5432/apac_db" \
--referenceUrl="jdbc:postgresql://apac-staging.internal:5432/apac_db" \
--username=apac_migrator \
--password="${APAC_DB_PASSWORD}" \
--changelogFile=apac-prod-missing-changes.yaml \
diffChangeLog
Atlas: Declarative Schema-as-Code for APAC Platform Teams
The Atlas model: declare state, generate diff
# schema.hcl: Desired APAC PostgreSQL schema state
schema "apac_core" {}
table "apac_customer_accounts" {
schema = schema.apac_core
column "account_id" {
type = uuid
default = sql("gen_random_uuid()")
}
column "customer_id" {
type = uuid
null = false
}
column "country_code" {
type = char(2)
null = false
comment = "APAC ISO 3166-1 alpha-2 country code"
}
column "account_balance" {
type = decimal(18, 4)
null = false
default = 0
}
column "currency_code" {
type = char(3)
null = false
comment = "APAC ISO 4217 currency code"
}
column "created_at" {
type = timestamptz
default = sql("NOW()")
}
primary_key {
columns = [column.account_id]
}
index "idx_apac_customer_id" {
columns = [column.customer_id]
}
index "idx_apac_country_balance" {
columns = [column.country_code, column.account_balance]
}
}
# Atlas: inspect current APAC database schema
atlas schema inspect \
--url "postgres://apac_migrator:${APAC_DB_PASSWORD}@apac-db.internal:5432/apac_db" \
--schema apac_core \
> current_schema.hcl
# Atlas: compute diff between desired and current APAC state
atlas schema diff \
--from "postgres://apac_migrator:${APAC_DB_PASSWORD}@apac-db.internal:5432/apac_db?search_path=apac_core" \
--to "file://schema.hcl"
# Atlas: apply APAC schema to match desired state (with dry-run first)
atlas schema apply \
--url "postgres://apac_migrator:${APAC_DB_PASSWORD}@apac-db.internal:5432/apac_db?search_path=apac_core" \
--to "file://schema.hcl" \
--dry-run # Remove for actual APAC application
Atlas versioned migrations for APAC CI/CD
# Atlas generates versioned migrations from schema diff
atlas migrate diff add_kyc_columns \
--dir "file://db/migrations" \
--to "file://schema.hcl" \
--dev-url "docker://postgres/15/apac_dev"
# Generated migration file (Atlas writes the SQL)
cat db/migrations/20260428121500_add_kyc_columns.sql
# -- atlas:name add_kyc_columns
# ALTER TABLE "apac_core"."apac_customer_accounts"
# ADD COLUMN "kyc_status" VARCHAR(20) NOT NULL DEFAULT 'pending',
# ADD COLUMN "kyc_verified_at" TIMESTAMPTZ,
# ADD COLUMN "kyc_provider" VARCHAR(50);
Atlas GitHub Actions for APAC PR schema review
# .github/workflows/apac-schema-review.yml
name: APAC Schema Migration Lint
on:
pull_request:
paths:
- 'db/migrations/**'
- 'schema.hcl'
jobs:
atlas-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Atlas lint APAC migrations
uses: ariga/atlas-action/migrate/lint@v1
with:
dir: db/migrations
dir-format: atlas
dev-url: "docker://postgres/15/apac_dev"
# Blocks APAC PRs containing:
# - DROP TABLE / DROP COLUMN without prior data migration
# - NOT NULL column additions without DEFAULT
# - Index removals that break APAC query plans
APAC Database Migration Tool Selection
APAC Team Profile → Tool → Reason
SQL-fluent engineers, explicit → Flyway Write exact APAC SQL; no abstraction;
control, CI/CD native → fastest to adopt; Docker-native
Enterprise APAC DBA team, → Liquibase Changeset audit trail; auto rollback
Oracle/SQL Server, compliance audit → generation; multi-DB dialect support
Platform engineering, Terraform → Atlas Declarative schema-as-code; drift
workflows, PostgreSQL/MySQL → detection; automated APAC SQL generation
APAC brownfield Oracle database, → Liquibase Liquibase diff + diffChangeLog
unknown schema state → reconstructs APAC changeset history
APAC greenfield service, → Atlas Start from desired state; Atlas
PostgreSQL, IaC-first culture → generates all APAC migration SQL
APAC Laravel/Django/Rails app → Framework Use built-in ORM migrations for
(ORM-managed schema) migrations APAC application-owned schema;
reserve Flyway/Liquibase/Atlas
for APAC shared/platform databases
Related APAC Data Infrastructure Resources
For the distributed databases that APAC migration tooling manages at scale, see the APAC distributed database guide covering TiDB, CockroachDB, and Valkey.
For the supply chain security scanning that runs alongside APAC database migration CI/CD gates, see the APAC supply chain security guide covering Checkov, Gitleaks, and TruffleHog.
For the CI/CD platform engineering tools that host APAC migration pipelines, see the APAC CI/CD platform engineering guide covering Tekton, Buildkite, and Gradle.
Beyond this insight
Cross-reference our practice depth.
If this article matches your stage of thinking, the underlying capabilities ship across all six pillars, ten verticals, and nine Asian markets.