Database Migration Tools Open Source Terbaik 2024

by Marcus Chen
Database Migration Tools Open Source Terbaik 2024

Kamu pernah nggak, lagi enak-enak deploy ke production, tiba-tiba aplikasi crash karena schema database di server beda sama yang di local? Kolom user_role yang kamu tambah minggu lalu ternyata belum ada di production. Panik. Rollback manual. Log error di mana-mana.

Itu bukan masalah kamu sendirian. Itu masalah klasik yang muncul ketika tim (atau kamu sendiri sebagai solo dev) nggak punya sistem yang proper buat ngelola perubahan schema database.

Solusinya: database migration tools. Dan kabar baiknya, ada banyak database migration tools open source yang production-ready, gratis, dan nggak butuh vendor lock-in.

Artikel ini bahas empat tools yang gue sendiri pernah pakai, bukan sekadar list dari dokumentasi resmi.


Kenapa Migration Manual Itu Bom Waktu

Sebelum masuk ke tools, penting buat ngerti dulu kenapa cara lama — nulis SQL manual terus dijalanin langsung di server — itu berbahaya.

  1. Nggak ada history. Kamu nggak tahu siapa yang alter tabel kapan.
  2. Nggak reproducible. Setup database di mesin baru jadi mimpi buruk.
  3. Rollback susah. Kalau ada yang salah, kamu harus inget apa yang diubah.
  4. Konflik di tim. Dua orang alter kolom yang sama di branch berbeda — selamat datang di hell.

Migration tools ngatasin semua ini dengan cara yang simpel: setiap perubahan schema disimpan sebagai file yang bisa di-version control bareng kode kamu.


1. Flyway — Simpel, Berbasis SQL Murni

Flyway adalah pilihan paling straightforward kalau kamu udah familiar dengan SQL dan nggak mau belajar DSL baru. Kamu nulis file SQL biasa, Flyway yang urus urutannya.

Install via Docker (cara paling gampang):

docker pull flyway/flyway

Struktur folder migration:

db/
  migrations/
    V1__create_users_table.sql
    V2__add_user_role_column.sql
    V3__create_posts_table.sql

Naming convention-nya ketat: V{versi}__{deskripsi}.sql. Dua underscore, bukan satu.

Isi file V2__add_user_role_column.sql:

ALTER TABLE users
ADD COLUMN user_role VARCHAR(50) NOT NULL DEFAULT 'viewer';

Jalanin migration:

docker run --rm \
  -v $(pwd)/db/migrations:/flyway/sql \
  flyway/flyway \
  -url=jdbc:postgresql://host.docker.internal:5432/mydb \
  -user=postgres \
  -password=secret \
  migrate

Flyway nyimpen state di tabel flyway_schema_history di database kamu. Jadi dia tahu migration mana yang udah dijalanin dan mana yang belum.

Gotcha yang gue kena: Flyway versi community nggak support undo/rollback migration. Kalau kamu butuh rollback, kamu harus bikin migration baru yang nge-revert perubahan sebelumnya. Ini sebenarnya best practice juga — forward-only migration lebih predictable.


2. Liquibase — Lebih Fleksibel, Support YAML/JSON/XML

Liquibase mirip Flyway tapi lebih powerful. Kamu bisa nulis migration dalam format SQL, YAML, JSON, atau XML. Ini berguna kalau kamu mau migration yang lebih readable atau database-agnostic.

Install:

# macOS
brew install liquibase

# atau download binary langsung
wget https://github.com/liquibase/liquibase/releases/download/v4.26.0/liquibase-4.26.0.tar.gz

Contoh changelog dalam YAML (db/changelog/db.changelog-master.yaml):

databaseChangeLog:
  - changeSet:
      id: 1
      author: marcus
      changes:
        - createTable:
            tableName: users
            columns:
              - column:
                  name: id
                  type: BIGINT
                  autoIncrement: true
                  constraints:
                    primaryKey: true
              - column:
                  name: email
                  type: VARCHAR(255)
                  constraints:
                    nullable: false
                    unique: true
              - column:
                  name: created_at
                  type: TIMESTAMP
                  defaultValueComputed: CURRENT_TIMESTAMP

  - changeSet:
      id: 2
      author: marcus
      changes:
        - addColumn:
            tableName: users
            columns:
              - column:
                  name: user_role
                  type: VARCHAR(50)
                  defaultValue: viewer
                  constraints:
                    nullable: false

Jalanin migration:

liquibase \
  --url=jdbc:postgresql://localhost:5432/mydb \
  --username=postgres \
  --password=secret \
  --changeLogFile=db/changelog/db.changelog-master.yaml \
  update

Cek status:

liquibase status --verbose

Output-nya bakal kasih tahu changeset mana yang belum diapply.

Gotcha: Liquibase butuh Java runtime. Kalau kamu nggak mau install Java, pakai Docker image-nya atau pakai Flyway yang lebih lightweight.


3. golang-migrate — Untuk Stack Go atau CLI Lover

Kalau kamu pakai Go, atau kamu cuma mau CLI tool yang ringan tanpa dependency Java, golang-migrate adalah jawabannya. Ini pure Go binary, single file, langsung jalan.

Install:

# macOS/Linux
curl -L https://github.com/golang-migrate/migrate/releases/download/v4.17.0/migrate.linux-amd64.tar.gz | tar xvz
sudo mv migrate /usr/local/bin/

# atau via Go
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest

Buat file migration baru:

migrate create -ext sql -dir db/migrations -seq create_users_table

Perintah ini otomatis bikin dua file:

  • 000001_create_users_table.up.sql — untuk apply migration
  • 000001_create_users_table.down.sql — untuk rollback

Isi 000001_create_users_table.up.sql:

CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL UNIQUE,
    user_role VARCHAR(50) NOT NULL DEFAULT 'viewer',
    created_at TIMESTAMP NOT NULL DEFAULT NOW()
);

Isi 000001_create_users_table.down.sql:

DROP TABLE IF EXISTS users;

Jalanin migration:

# Apply semua migration
migrate -path db/migrations -database "postgres://postgres:secret@localhost:5432/mydb?sslmode=disable" up

# Rollback 1 step
migrate -path db/migrations -database "postgres://postgres:secret@localhost:5432/mydb?sslmode=disable" down 1

Integrasi di kode Go kamu:

package main

import (
    "log"

    "github.com/golang-migrate/migrate/v4"
    _ "github.com/golang-migrate/migrate/v4/database/postgres"
    _ "github.com/golang-migrate/migrate/v4/source/file"
)

func runMigrations(databaseURL string) {
    m, err := migrate.New(
        "file://db/migrations",
        databaseURL,
    )
    if err != nil {
        log.Fatalf("Failed to initialize migrate: %v", err)
    }
    defer m.Close()

    if err := m.Up(); err != nil && err != migrate.ErrNoChange {
        log.Fatalf("Migration failed: %v", err)
    }

    log.Println("Database migration completed")
}

Gotcha penting: Kalau migration kamu pernah gagal di tengah jalan (misalnya koneksi putus), golang-migrate bakal mark versi itu sebagai "dirty". Kamu perlu resolve manual:

migrate -path db/migrations -database "..." force 1

Angka 1 adalah versi migration terakhir yang berhasil. Ini agak annoying tapi setidaknya transparan.


4. Atlas — Modern, Schema-as-Code

Atlas adalah pendatang baru yang menarik. Pendekatan dia beda: kamu define desired state schema kamu, Atlas yang hitung diff-nya dan generate migration SQL.

Install:

curl -sSf https://atlasgo.sh | sh

Define schema di file HCL (schema.hcl):

table "users" {
  schema = schema.public
  column "id" {
    null = false
    type = bigserial
  }
  column "email" {
    null = false
    type = varchar(255)
  }
  column "user_role" {
    null    = false
    type    = varchar(50)
    default = "viewer"
  }
  column "created_at" {
    null    = false
    type    = timestamp
    default = sql("now()")
  }
  primary_key {
    columns = [column.id]
  }
  index "users_email_key" {
    unique  = true
    columns = [column.email]
  }
}

Apply schema langsung (dev mode):

atlas schema apply \
  --url "postgres://postgres:secret@localhost:5432/mydb?sslmode=disable" \
  --to file://schema.hcl

Atlas bakal tunjukin diff dan minta konfirmasi sebelum execute.

Generate migration files (untuk production workflow):

atlas migrate diff add_user_role \
  --dir "file://db/migrations" \
  --to file://schema.hcl \
  --dev-url "docker://postgres/15/dev"

Atlas butuh dev database buat generate diff yang akurat. Dia spin up container sementara kalau kamu kasih docker:// URL — ini cukup magic tapi juga berarti kamu butuh Docker.

Gotcha: HCL syntax Atlas punya learning curve. Kalau kamu prefer SQL biasa, Atlas juga support format SQL untuk schema definition-nya.


Perbandingan Singkat: Pilih yang Mana?

Tool Format Rollback Dependency Cocok untuk
Flyway SQL Manual (migration baru) Java/Docker Tim yang familiar SQL
Liquibase SQL/YAML/XML Built-in (terbatas) Java Multi-database, enterprise
golang-migrate SQL Built-in (down files) Go binary Go projects, CLI lovers
Atlas HCL/SQL Diff-based Go binary Schema-first approach

Kalau kamu baru mulai dan stack-nya bebas, golang-migrate adalah rekomendasi gue. Ringan, nggak butuh Java, rollback jelas dengan .down.sql files, dan dokumentasinya solid.

Kalau kamu udah di ekosistem Java atau butuh support banyak database sekaligus, Liquibase worth it.


Integrasi dengan CI/CD Pipeline

Migration tools ini baru berguna maksimal kalau diintegrasikan ke pipeline kamu. Contoh sederhana dengan GitHub Actions:

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  migrate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install golang-migrate
        run: |
          curl -L https://github.com/golang-migrate/migrate/releases/download/v4.17.0/migrate.linux-amd64.tar.gz | tar xvz
          sudo mv migrate /usr/local/bin/

      - name: Run database migrations
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
        run: |
          migrate -path db/migrations -database "$DATABASE_URL" up

Jalanin migration sebelum deploy aplikasi baru. Urutan ini penting buat backward compatibility.


Yang Gue Lakuin Sekarang

Untuk project solo gue sekarang, gue pakai golang-migrate karena stack-nya Go dan gue suka punya kontrol penuh atas SQL yang dijalanin. Setup-nya cuma butuh sekitar 15 menit dari nol sampai migration pertama jalan.

Beberapa hal yang langsung gue terapkan setelah pakai migration tools:

  • Semua perubahan schema masuk Git, nggak ada lagi SQL yang diketik langsung di production terminal.
  • Setiap PR yang ubah schema wajib include migration file, di-review bareng kode.
  • Rollback jadi ada prosedurnya, bukan panik dan coba-coba.

Kalau kamu belum pakai database migration tools sama sekali, mulai dari project yang paling kecil dulu. Bikin satu migration file untuk schema yang udah ada (V1__initial_schema.sql), commit, dan rasain bedanya. Dari situ natural bakal ketagihan.

Database migration tools open source ini semua gratis, battle-tested, dan komunitas support-nya aktif. Nggak ada alasan buat tetap migration manual di 2024.