Menambahkan kolom baru, mengubah nama tabel, atau mengganti format data sering terlihat seperti pekerjaan sederhana. Masalahnya, database aplikasi web biasanya sudah dipakai oleh banyak bagian sekaligus: halaman frontend, API, laporan, job terjadwal, hingga integrasi dengan layanan lain. Satu perubahan yang dilakukan langsung di produksi dapat menimbulkan error yang baru terlihat setelah pengguna mengakses fitur tertentu.
Di sinilah database migration membantu. Migration adalah catatan perubahan struktur database yang dibuat dalam bentuk file dan dijalankan secara terurut. Dengan cara ini, tim tidak hanya tahu seperti apa kondisi database sekarang, tetapi juga dapat melacak bagaimana database sampai ke kondisi tersebut.
Mengapa perubahan database perlu diperlakukan seperti kode?
Tanpa migration, perubahan database sering dilakukan secara manual melalui aplikasi seperti phpMyAdmin atau perintah SQL yang hanya tersimpan di komputer seseorang. Cara ini mungkin cukup untuk proyek kecil, tetapi cepat menjadi masalah ketika ada beberapa developer, lebih dari satu server, atau proses deployment yang harus diulang.
Bayangkan seorang developer menambahkan kolom phone_number di laptopnya, tetapi lupa menerapkan perubahan yang sama di server staging. Kode terbaru kemudian dites dan terlihat gagal karena kolom tersebut belum ada. Situasi lain bisa lebih berbahaya: perubahan sudah dilakukan di produksi, tetapi tidak ada catatan perintah yang jelas ketika tim perlu menyiapkan server baru.
Migration membuat perubahan database menjadi bagian dari source code. Perubahan dapat ditinjau melalui pull request, diuji di staging, dan dijalankan dengan urutan yang konsisten.
Contoh perubahan yang sebaiknya menggunakan migration
- Menambahkan tabel baru, misalnya
ordersatauinvoices. - Menambahkan kolom seperti
status,created_at, atauuser_id. - Membuat atau menghapus index untuk memperbaiki performa query.
- Mengubah relasi antar tabel.
- Memindahkan data dari struktur lama ke struktur baru.
- Mengubah tipe data atau aturan
NULLpada kolom.
Framework seperti Laravel, Symfony, Rails, Django, dan berbagai tool database menyediakan sistem migration. Namun, prinsipnya tetap sama meskipun Anda menggunakan PHP murni atau menjalankan SQL secara langsung.
Prinsip penting: perubahan harus bisa dilacak
File migration biasanya memiliki nama yang mengandung waktu atau nomor urut. Misalnya, sebuah proyek PHP dapat memiliki file seperti 2026_09_24_100000_add_status_to_orders.php. Nama tersebut memberi petunjuk kapan perubahan dibuat dan apa tujuannya.
Isi migration sebaiknya fokus pada satu perubahan yang jelas. Jangan mencampur penambahan tabel pengguna, perubahan struktur pesanan, dan penghapusan data lama dalam satu file besar. Migration yang kecil lebih mudah dipahami, diuji, dan diperbaiki ketika terjadi masalah.
Jika tool yang digunakan mendukungnya, sediakan dua arah perubahan: proses untuk menerapkan perubahan dan proses untuk membatalkannya. Namun, rollback bukan berarti semua migration selalu aman dibatalkan. Penghapusan kolom atau data dapat menyebabkan informasi yang sudah hilang tidak bisa dipulihkan.
Jangan langsung membuat kolom baru menjadi wajib
Salah satu kesalahan umum adalah menambahkan kolom baru dengan aturan NOT NULL ketika tabel sudah berisi banyak data. Database akan menolak baris lama jika tidak ada nilai yang dapat mengisi kolom tersebut. Bahkan jika tool migration menyediakan nilai default, perubahan besar tetap bisa mengunci tabel atau memperlambat aplikasi.
Pola yang lebih aman adalah melakukan perubahan dalam beberapa tahap:
- Tambahkan kolom baru sebagai nullable atau dengan nilai default yang aman.
- Deploy kode yang mulai menulis data ke kolom baru, tanpa langsung berhenti membaca kolom lama.
- Isi data lama secara bertahap menggunakan script atau proses background.
- Pastikan seluruh aplikasi sudah memakai kolom baru.
- Baru kemudian, jika memang diperlukan, ubah kolom menjadi wajib dan hapus struktur lama.
Pola ini dikenal sebagai expand and contract. Tahap expand menambahkan struktur baru tanpa memutus kompatibilitas. Tahap contract membersihkan struktur lama setelah tidak lagi digunakan.
Contoh sederhana perubahan yang kompatibel
Misalnya, aplikasi sebelumnya menyimpan nama lengkap dalam kolom full_name. Anda ingin memisahkannya menjadi first_name dan last_name. Jangan langsung menghapus full_name pada deployment pertama.
Migration pertama menambahkan dua kolom baru:
ALTER TABLE users
ADD COLUMN first_name VARCHAR(100) NULL,
ADD COLUMN last_name VARCHAR(100) NULL;Setelah itu, kode aplikasi dapat menulis ke kolom baru sambil tetap membaca full_name sebagai cadangan. Data lama dipindahkan secara bertahap. Jika semua bagian aplikasi sudah menggunakan kolom baru, barulah kolom lama dapat dihapus melalui migration terpisah.
Contoh ini juga menunjukkan bahwa migration bukan hanya soal SQL. Ia perlu dirancang bersama perubahan kode aplikasi, proses pengisian data, dan strategi deployment.
Perhatikan index dan ukuran tabel
Menambahkan index dapat mempercepat pencarian, tetapi proses pembuatannya juga dapat memakai banyak CPU, memori, dan waktu. Pada tabel kecil, dampaknya mungkin tidak terasa. Pada tabel yang berisi jutaan baris, pembuatan index secara langsung dapat mengganggu query pengguna.
Sebelum membuat index, periksa query yang memang sering dijalankan. Index sebaiknya dibuat berdasarkan kebutuhan nyata, bukan sekadar menambahkan index ke semua kolom. Perhatikan juga urutan kolom pada index gabungan karena urutan tersebut memengaruhi query yang dapat memakainya.
Untuk database besar, pelajari dukungan database yang digunakan terhadap pembuatan index secara online atau gunakan tool khusus yang dirancang untuk mengurangi lock. Detail teknisnya berbeda antara MySQL, PostgreSQL, dan sistem database lain, sehingga jangan mengandalkan asumsi dari proyek sebelumnya.
Uji migration sebelum menyentuh produksi
Migration sebaiknya dijalankan di lingkungan yang menyerupai produksi. Gunakan salinan struktur dan, bila memungkinkan, ukuran data yang mendekati kondisi nyata. Migration yang selesai dalam satu detik pada database kosong belum tentu aman ketika dijalankan pada tabel besar.
Checklist sederhana yang bisa digunakan:
- Jalankan migration pada database lokal yang bersih.
- Jalankan seluruh migration dari awal untuk memastikan urutannya benar.
- Uji migration pada staging dengan data yang realistis.
- Periksa durasi, penggunaan lock, dan dampaknya terhadap query.
- Siapkan backup dan prosedur pemulihan sebelum deployment.
- Tentukan cara memantau error setelah perubahan diterapkan.
Jangan menganggap rollback sebagai pengganti backup. Rollback struktur belum tentu mengembalikan data yang sudah berubah. Backup dan uji restore tetap menjadi bagian penting dari rencana perubahan database.
Apa artinya bagi kita?
Migration bukan formalitas untuk proyek besar saja. Pada aplikasi kecil sekalipun, migration membantu mengurangi ketergantungan pada ingatan satu orang dan membuat setup server baru lebih konsisten.
Mulailah dari kebiasaan sederhana: setiap perubahan schema harus memiliki file migration, satu tujuan yang jelas, dan diuji sebelum masuk produksi. Untuk perubahan yang berisiko, pecah proses menjadi beberapa deployment agar versi kode lama dan baru tetap dapat berjalan bersamaan.
Dengan pendekatan ini, perubahan database tidak lagi menjadi tindakan manual yang menegangkan. Ia berubah menjadi proses terencana yang bisa ditinjau, diuji, dipantau, dan jika perlu diperbaiki tanpa membuat seluruh aplikasi ikut berhenti.
– Rio Yotto @rioyotto
