Migrasi Database Produksi dengan Claude Code
Panduan Claude Code untuk migrasi DB produksi: expand/contract, Prisma, CI, backfill, lock, dan batas rollback.
Migrasi database produksi tidak aman jika dimulai dengan prompt samar seperti “ubah schema ini”. Risiko utamanya bukan hanya sintaks SQL. Risiko sebenarnya ada pada urutan kerja: deploy aplikasi, database lock, backup, backfill data, feature flag, pemeriksaan CI, dan keputusan rollback.
Claude Code berguna ketika dipakai sebagai reviewer terlebih dahulu, lalu sebagai asisten implementasi. Ia berbahaya jika langsung diminta membuat migration besar dan hasilnya diterapkan tanpa pemisahan tahap. Panduan ini memakai contoh PostgreSQL dan Prisma Migrate, tetapi pola yang sama berlaku untuk migration SQL manual.
Saat review, buka sumber resmi: dokumentasi Claude Code, PostgreSQL tentang explicit locking dan ALTER TABLE, Prisma tentang development and production dan CLI reference, serta GitHub Actions workflow syntax.
Model expand/contract
Model paling aman adalah expand/contract. Expand berarti memperluas database agar versi lama dan versi baru aplikasi bisa berjalan bersamaan. Contract berarti menghapus kolom lama, jalur baca lama, atau constraint sementara hanya setelah jalur baru stabil di produksi.
flowchart LR
A["Backup and review"]
B["Expand: add nullable column or new table"]
C["Deploy code with dual write or feature flag"]
D["Backfill data in small batches"]
E["Validate staging and production metrics"]
F["Contract: add NOT NULL, remove old path"]
A --> B --> C --> D --> E --> F
Kesalahan umum adalah meminta Claude Code menambahkan kolom, menyalin data, memasang NOT NULL, lalu menghapus kolom lama dalam satu migration. Itu bisa lolos di database lokal kecil. Di tabel users atau orders berisi jutaan baris, pola itu dapat memicu lock panjang, write terblokir, timeout, atau kehilangan data.
Beberapa istilah perlu jelas. Lock adalah mekanisme database untuk mencegah operasi paralel yang tidak kompatibel. Backfill adalah proses mengisi kolom baru untuk baris lama. Shadow database adalah database sementara yang dipakai Prisma di development untuk memutar ulang migration history dan mendeteksi drift. Itu bukan pengaman otomatis untuk produksi.
Mulai dari review prompt
Prompt pertama harus meminta review, bukan edit file. Beri Claude Code ukuran tabel, cara deploy, ORM, dan ekspektasi recovery.
Review this database migration plan before editing files.
Context:
- Production database: PostgreSQL
- ORM: Prisma Migrate
- Hot tables: users has about 8 million rows, orders has about 25 million rows
- Deploy style: blue/green app deploy, database migration runs in CI/CD
- Requirement: split users.name into users.full_name and users.display_name
Check:
1. Can old and new app versions run at the same time?
2. Which SQL statements may take strong locks or scan the whole table?
3. Which steps must be expand, backfill, validate, and contract?
4. What backup or point-in-time recovery check is needed before deploy?
5. What can be rolled back by app deploy, and what can only be rolled forward?
Return a migration plan first. Do not edit files yet.
Kalimat terakhir penting. Claude Code dapat bergerak cepat, tetapi migrasi database butuh jeda desain. Jika rencana pertama mencampur langkah berbahaya, minta versi yang lebih konservatif.
Rewrite the plan so that no step drops a column, rewrites a large table, or sets NOT NULL before the backfill is verified. Include a staging rehearsal and a production abort condition.
Dengan cara ini, Claude Code berperan sebagai migration reviewer. Manusia tetap memutuskan risiko, sedangkan agent membantu menyusun file, perintah, SQL, pemeriksaan CI, dan pertanyaan monitoring.
SQL untuk expand
Misalnya users.name akan diganti oleh full_name dan display_name. Migration expand hanya menambahkan kolom nullable dan indeks. Tidak ada backfill, tidak ada NOT NULL, dan tidak ada penghapusan users.name.
-- 20260602090000_expand_users_names.sql
-- Keep this migration small. Do not backfill and do not drop users.name here.
ALTER TABLE users
ADD COLUMN full_name text,
ADD COLUMN display_name text;
-- Run outside a transaction in PostgreSQL migration tools that support it.
-- CREATE INDEX CONCURRENTLY cannot run inside a transaction block.
CREATE INDEX CONCURRENTLY IF NOT EXISTS users_display_name_idx
ON users (display_name);
Dokumentasi ALTER TABLE PostgreSQL menjelaskan bahwa subcommand berbeda dapat mengambil level lock berbeda. Jika tidak ada keterangan lock yang lebih ringan, review harus konservatif. Jangan biarkan Claude Code menebak. Minta ia mengaitkan analisis dengan dokumen resmi.
Dengan Prisma, buat migration tanpa menerapkannya, lalu review SQL.
npx prisma migrate dev --name expand-users-names --create-only
npx prisma validate
Panduan Prisma menyebut npx prisma migrate deploy sebagai perintah untuk test dan production. Panduan yang sama menjelaskan bahwa migrate deploy menerapkan pending migrations, tetapi tidak mendeteksi drift dan tidak bergantung pada shadow database. Jadi command yang sukses belum berarti rehearsal produksi selesai.
npx prisma migrate deploy
Ubah aplikasi secara kompatibel
Setelah expand, aplikasi harus tahan terhadap schema lama dan baru. Read path membutuhkan fallback, dan write path perlu mengisi field lama serta baru selama masa transisi.
// src/domain/userName.ts
type UserNameRow = {
name: string | null;
fullName: string | null;
displayName: string | null;
};
export function readDisplayName(user: UserNameRow): string {
return user.displayName ?? user.fullName ?? user.name ?? "Unknown user";
}
export function buildNameUpdate(input: { name: string }) {
const normalized = input.name.trim().replace(/\s+/g, " ");
return {
name: normalized,
fullName: normalized,
displayName: normalized.length > 40 ? `${normalized.slice(0, 39)}...` : normalized,
};
}
Feature flag memisahkan perubahan database dari perilaku yang terlihat oleh pengguna. Biarkan jalur baca baru mati selama backfill, nyalakan setelah validasi, dan matikan lagi jika muncul error. Untuk implementasi, lihat panduan internal feature flags dengan Claude Code.
Pola ini berguna untuk beberapa kasus nyata: rename atau split field profil, menambahkan kolom hasil perhitungan seperti saldo invoice atau label pencarian, dan menambah index atau foreign key pada tabel yang ramai. Semuanya lebih aman jika dipisah menjadi expand, deploy aplikasi, backfill, validasi, dan contract.
Backfill dalam batch kecil
Satu UPDATE besar dapat memperbesar lock time, volume WAL, replication lag, dan risiko operasional. Lebih baik minta Claude Code membuat script batch yang bisa dijalankan ulang.
// scripts/backfill-user-names.mjs
import pg from "pg";
const { Client } = pg;
const batchSize = Number(process.env.BATCH_SIZE ?? 1000);
const sleepMs = Number(process.env.SLEEP_MS ?? 200);
const client = new Client({ connectionString: process.env.DATABASE_URL });
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
await client.connect();
try {
let total = 0;
while (true) {
const result = await client.query(
`
WITH target AS (
SELECT id, name
FROM users
WHERE full_name IS NULL
AND name IS NOT NULL
ORDER BY id
LIMIT $1
FOR UPDATE SKIP LOCKED
)
UPDATE users AS u
SET
full_name = target.name,
display_name = CASE
WHEN length(target.name) > 40 THEN substring(target.name from 1 for 39) || '...'
ELSE target.name
END
FROM target
WHERE u.id = target.id
RETURNING u.id
`,
[batchSize],
);
total += result.rowCount;
console.log(`updated=${result.rowCount} total=${total}`);
if (result.rowCount === 0) break;
await sleep(sleepMs);
}
} finally {
await client.end();
}
Sebelum produksi, review idempotency, kegagalan sebagian, eksekusi paralel, dan kontrol operasi. Backfill yang baik memiliki batch size, jeda, log, kondisi berhenti, dan query yang aman dijalankan ulang.
CI dan staging
CI sebaiknya menerapkan seluruh migration history pada database sementara. Di GitHub Actions, workflow berada di .github/workflows dan ditulis sebagai YAML.
name: migration-check
on:
pull_request:
paths:
- "prisma/**"
- "scripts/backfill-*.mjs"
- ".github/workflows/migration-check.yml"
jobs:
prisma-migrations:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: app
ports:
- "5432:5432"
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/app?schema=public
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
- run: npm ci
- run: npx prisma validate
- run: npx prisma migrate deploy
- run: npx prisma migrate status
- name: Detect schema drift after migrations
run: |
npx prisma migrate diff \
--exit-code \
--from-config-datasource \
--to-schema=prisma/schema.prisma
Contoh ini memakai argumen Prisma ORM v7 berbasis config datasource. Jangan menyalin contoh lama yang memakai --from-url atau --shadow-database-url tanpa mengecek CLI reference terbaru.
Staging harus lebih realistis daripada CI: jumlah baris mendekati produksi, indeks serupa, timeout serupa, dan migration runner yang sama. Minta Claude Code membuat checklist untuk lock wait, replication lag, latency, log aplikasi, dan batas abort.
Contract dan batas rollback
Contract hanya dilakukan setelah aplikasi baru stabil dan backfill tervalidasi. Untuk NOT NULL, validasi dulu dengan constraint.
-- 20260602120000_contract_users_names.sql
-- Run only after the new application version has been stable in production.
ALTER TABLE users
ADD CONSTRAINT users_full_name_present
CHECK (full_name IS NOT NULL) NOT VALID;
ALTER TABLE users
VALIDATE CONSTRAINT users_full_name_present;
ALTER TABLE users
ALTER COLUMN full_name SET NOT NULL;
ALTER TABLE users
DROP CONSTRAINT users_full_name_present;
-- Drop old columns in a later deploy, not in the same deploy that changes reads.
-- ALTER TABLE users DROP COLUMN name;
Kesalahpahaman terbesar adalah mengira down migration selalu memulihkan data. Kolom yang sudah dihapus, nilai yang ditimpa, dan konversi tipe yang kehilangan presisi tidak kembali hanya dengan SQL terbalik. Biasanya yang bisa di-rollback adalah versi aplikasi atau feature flag. Untuk database, pikirkan backup, point-in-time recovery, atau forward fix.
prisma migrate resolve --rolled-back juga bukan perintah untuk membatalkan migration sukses. Itu dipakai untuk menyelesaikan status history setelah migration gagal. Minta Claude Code memisahkan app rollback, database forward fix, dan data restore dalam setiap rencana.
Kegagalan umum dan workflow tim
Kegagalan pertama adalah memperlakukan rename sebagai drop and add. ORM tidak selalu tahu niat kita, jadi SQL hasil generate harus dibaca. Kegagalan kedua adalah mencampur perubahan schema dan rewrite data besar dalam satu migration. Kegagalan ketiga adalah terlalu percaya shadow database. Ia membantu development drift, tetapi tidak mensimulasikan distribusi data produksi, bloat, antrean lock, atau replication lag. Kegagalan keempat adalah backup check hanya berupa asumsi.
Tulis aturan DB di CLAUDE.md: jangan drop column dari hot table di PR yang sama, jangan taruh backfill besar di schema migration, Prisma migration dibuat dengan --create-only untuk review SQL, dan review harus menyertakan link dokumentasi resmi. Untuk struktur, baca CLAUDE.md best practices.
Untuk SaaS yang menghasilkan revenue, migration buruk bisa menghentikan billing, signup, dan support. Produk ClaudeCodeLab menyediakan prompt dan checklist yang bisa dipakai ulang, sedangkan Claude Code training membantu menerapkan workflow ini di repository nyata.
Dari praktik langsung, peningkatan terbesar bukan SQL yang lebih rumit. Peningkatan datang saat satu migration mengerjakan lebih sedikit hal. PR expand-only, job backfill terpisah, dan PR contract belakangan membuat output Claude Code lebih mudah direview. Biasakan meminta abort condition dan recovery steps sebelum meminta SQL.
Ringkasan
Claude Code tidak otomatis membuat migration produksi aman. Ia menjadi kuat ketika tim memberi model yang aman: expand/contract, deploy aplikasi bertahap, backfill kecil, CI, rehearsal staging, feature flag, dan batas rollback yang eksplisit.
Untuk migration berikutnya, minta Claude Code melakukan risk review dulu. Jika rencananya masuk akal, baru biarkan ia menulis SQL, Prisma migration, workflow GitHub Actions, dan script backfill.
PDF gratis: cheatsheet Claude Code
Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.
Kami menjaga datamu dan tidak mengirim spam.
Tentang penulis
Masa
Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.
Artikel terkait
Workflow Obsidian ke CLAUDE.md untuk Claude Code
Ubah catatan kerja Obsidian menjadi operating note CLAUDE.md agar konteks tidak dijelaskan ulang.
Claude Code Revenue CTA Routing: dari artikel ke PDF, Gumroad, dan konsultasi
Workflow Claude Code untuk mengarahkan pembaca ke PDF gratis, Gumroad, atau konsultasi sesuai intent.
Aturan handoff tim Claude Code: bukti review, permission, rollback, dan jalur revenue
Format handoff Claude Code untuk tim: bukti, permission rule, rollback, PDF gratis, Gumroad, dan konsultasi.