Migrasi Database yang Aman di Laravel

Migration adalah cara Laravel melacak perubahan struktur database dalam bentuk kode, sehingga tim Anda selalu punya skema yang sama dan perubahan bisa dibalik jika salah. Tetapi mi...

Migrasi Database yang Aman di Laravel

Migration adalah cara Laravel melacak perubahan struktur database dalam bentuk kode, sehingga tim Anda selalu punya skema yang sama dan perubahan bisa dibalik jika salah. Tetapi migration yang ceroboh — terutama di produksi — bisa menyebabkan kehilangan data permanen. Artikel ini membahas cara membuat migration yang aman, dari dasar hingga strategi menjalankan migrasi di server produksi tanpa merusak data pengguna.

1. Membuat Tabel Baru

Setiap migration punya method up() (menerapkan perubahan) dan down() (membatalkannya). Buat migration dengan artisan:

php artisan make:migration create_products_table
public function up(): void
{
    Schema::create('products', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->integer('price');
        $table->timestamps();
    });
}

public function down(): void
{
    Schema::dropIfExists('products');
}

Selalu isi down() dengan benar. Method inilah yang membuat rollback aman.

2. Mengubah Tabel yang Sudah Ada

Jangan pernah mengedit file migration lama yang sudah dijalankan di produksi. Sebagai gantinya, buat migration BARU untuk setiap perubahan:

php artisan make:migration add_stock_to_products_table --table=products
public function up(): void
{
    Schema::table('products', function (Blueprint $table) {
        $table->integer('stock')->default(0)->after('price');
    });
}

public function down(): void
{
    Schema::table('products', function (Blueprint $table) {
        $table->dropColumn('stock');
    });
}

Untuk mengganti nama atau tipe kolom, pastikan package doctrine/dbal terpasang jika Anda memakai Laravel versi lama. Di Laravel 11, change() sudah didukung tanpa dependensi tambahan.

3. Foreign Key yang Benar

Foreign key menjaga integritas relasi antar tabel. Cara paling ringkas di Laravel modern:

Schema::create('orders', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')
          ->constrained()
          ->onDelete('cascade');
    $table->timestamps();
});

constrained() otomatis menautkan ke tabel users berdasarkan konvensi. onDelete('cascade') menghapus order saat user-nya dihapus. Gunakan dengan hati-hati — kadang nullOnDelete() lebih aman agar data tidak ikut terhapus.

4. Menghindari Kehilangan Data

Beberapa operasi bersifat merusak dan tidak bisa dibatalkan. Perhatikan hal berikut:

  • dropColumn menghapus kolom beserta seluruh isinya secara permanen. Pastikan datanya benar-benar tidak dibutuhkan.
  • Saat menambah kolom NOT NULL ke tabel yang sudah berisi data, wajib beri default() atau jadikan nullable(). Tanpa itu migration akan gagal.
  • Sebelum migration destruktif di produksi, selalu backup database terlebih dahulu.
// Aman: kolom baru punya nilai default
$table->string('status')->default('pending');
// atau
$table->string('phone')->nullable();

5. Menjalankan Migrasi di Produksi

Di lokal Anda memakai php artisan migrate. Di produksi, Laravel akan meminta konfirmasi karena khawatir merusak data. Untuk deployment otomatis, gunakan flag --force:

php artisan migrate --force

Selalu jalankan ini setelah backup, dan idealnya dalam mode maintenance:

php artisan down          # aktifkan mode maintenance
php artisan migrate --force
php artisan up            # kembali online

Untuk membatalkan batch migration terakhir jika terjadi masalah:

php artisan migrate:rollback

6. Tips Zero-Downtime

Menambah kolom besar atau index pada tabel jutaan baris bisa mengunci tabel dan membuat aplikasi tidak responsif. Beberapa strategi:

  • Pisahkan perubahan bertahap: tambahkan kolom baru (nullable) di satu deploy, isi datanya, baru terapkan constraint di deploy berikutnya.
  • Hindari mengubah kolom yang sedang dipakai kode lama: pastikan kode dan skema kompatibel di kedua arah selama transisi.
  • Untuk MySQL besar, pertimbangkan tool seperti pt-online-schema-change agar perubahan tidak mengunci tabel.

7. Seeder untuk Data Awal

Seeder mengisi database dengan data awal atau data contoh. Buat dengan artisan:

php artisan make:seeder RoleSeeder
public function run(): void
{
    Role::insert([
        ['name' => 'admin'],
        ['name' => 'member'],
    ]);
}

Jalankan seeder tanpa mengulang seluruh migrasi:

php artisan db:seed --class=RoleSeeder

Untuk data referensi yang harus ada di produksi (misalnya daftar role atau kategori), gunakan updateOrInsert() di dalam seeder agar aman dijalankan berulang tanpa membuat duplikat.

8. Memeriksa Status Migrasi

Sebelum menjalankan migrasi di server, penting mengetahui migration mana yang sudah dan belum dijalankan. Laravel menyediakan perintah untuk itu:

php artisan migrate:status

Perintah ini menampilkan daftar migration beserta tanda apakah sudah dijalankan (Ran) atau belum (Pending). Kebiasaan mengeceknya sebelum deploy mencegah Anda menjalankan migration yang tidak sengaja tertinggal atau menjalankan ulang yang sudah diterapkan.

Hindari juga perintah berikut di produksi kecuali Anda benar-benar yakin, karena akan menghapus SEMUA tabel lalu membuat ulang dari nol:

php artisan migrate:fresh   // BERBAHAYA di produksi: menghapus semua data
php artisan migrate:refresh // rollback semua lalu migrate ulang

Kedua perintah ini sangat berguna saat pengembangan lokal, tetapi di produksi cukup pakai migrate --force yang hanya menjalankan migration baru tanpa menyentuh data yang sudah ada.

Kesimpulan

Migration yang aman berpijak pada beberapa aturan sederhana: jangan pernah mengedit migration lama, selalu isi down(), beri nilai default saat menambah kolom NOT NULL, dan backup sebelum operasi destruktif di produksi. Periksa migrate:status sebelum deploy, dan jauhi migrate:fresh di server hidup. Dengan migrate --force di dalam mode maintenance serta strategi bertahap untuk tabel besar, Anda bisa mengembangkan skema database tanpa takut kehilangan data pengguna.

Strategi Rollback dan Pencadangan

Migrasi yang aman selalu menyiapkan jalan mundur. Sebelum menjalankan migrasi di lingkungan produksi, buat cadangan penuh basis data agar Anda dapat memulihkan kondisi bila terjadi kegagalan. Rancang setiap migrasi agar dapat dibatalkan melalui metode down yang benar, sehingga perubahan bisa digulung balik tanpa merusak data. Untuk perubahan besar, uji terlebih dahulu di lingkungan staging yang menyerupai produksi, lalu jalankan pada jam sepi untuk meminimalkan dampak ke pengguna. Hindari menghapus kolom atau tabel secara langsung; lebih aman menonaktifkannya dulu, memastikan tidak ada yang bergantung padanya, baru menghapus di migrasi terpisah. Dengan disiplin pencadangan dan rollback, migrasi database menjadi proses yang terkendali dan bebas kepanikan meski terjadi hal tak terduga.

Yudhi
Ditulis oleh
Yudhi
Founder & Lead Developer, GudangCode

Yudhi adalah founder GudangCode dan developer Laravel dengan pengalaman membangun puluhan sistem informasi bisnis siap pakai — mulai dari POS, HRIS, hingga aplikasi manajemen. Ia menulis panduan dan artikel di GudangCode untuk membantu developer Indonesia menjalankan, memahami, dan men-deploy source code Laravel dengan benar.

Laravel PHP MySQL Sistem Informasi Bisnis
Lihat semua artikel Yudhi
Mau source code & aplikasi lengkapnya?

Daftar gratis untuk mengunduh aplikasi bisnis, sistem informasi, dan source code Laravel siap pakai.

Daftar Gratis & Download
Migration Laravel Programming & Laravel
📚 Free Learning Hub

Learn Coding for Free at DhieCoderWeb

Explore Laravel, PHP, JavaScript tutorials, source code, web development guides, and practical programming tips.

DhieCoderWeb
100+
Tutorials
Free
Learning
SEO
Tips
Visit Dhiecoderweb.com →

Dapatkan Akses Penuh Sekarang!

Bergabunglah menjadi member kami dan dapatkan akses eksklusif ke seluruh fitur unggulan aplikasi ini. Proses cepat, mudah, dan langsung bisa Anda gunakan.

Daftar Members Sekarang
Tim Support
Online
Isi data dulu untuk mulai chat:
Beri rating & testimoni sebelum menutup:
Live chat by gudangcode.com