Migration: Version Control untuk Database
Buat dan jalankan migration: skema database sebagai kode.
Konsep: Git untuk Database
Bayangkan kamu dan dua teman mengerjakan satu aplikasi. Temanmu menambah kolom harga ke tabel produks lewat phpMyAdmin di laptopnya. Tabel di laptopmu tidak ikut berubah, aplikasimu error, dan tidak ada yang tahu persis apa yang diubah. Kekacauan klasik.
Migration menyelesaikan ini dengan menjadikan skema database sebagai kode. Setiap perubahan struktur (bikin tabel, tambah kolom) ditulis sebagai file PHP di database/migrations, di-commit ke Git seperti kode biasa, dan dijalankan dengan php artisan migrate di laptop siapa pun atau di server mana pun. Hasilnya: semua environment punya struktur database yang identik, dan setiap perubahan tercatat rapi seperti commit Git.
Contoh 1: Membuat dan Menjalankan Migration
php artisan make:migration create_posts_tablePerintah ini membuat file seperti database/migrations/2026_10_08_120000_create_posts_table.php (timestamp di depan memastikan urutan eksekusi). Isi dengan definisi tabel:
File: database/migrations/2026_10_08_120000_create_posts_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};up() dijalankan saat migrate, down() saat rollback. Lalu:
php artisan migrateLaravel mencatat migration yang sudah jalan di tabel migrations, jadi file yang sama tidak akan dijalankan dua kali.
Contoh 2: Relasi dan Tipe Kolom yang Sering Dipakai
File: database/migrations/2026_10_08_120100_create_comments_table.php
return new class extends Migration {
public function up(): void
{
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->string('nama', 100);
$table->text('isi');
$table->boolean('disetujui')->default(false);
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('comments');
}
};foreignId('post_id')->constrained() membuat kolom unsigned bigint plus foreign key ke tabel posts. cascadeOnDelete() berarti komentar ikut terhapus kalau post-nya dihapus. Tipe umum lain: integer(), decimal(10, 2) untuk uang, date(), timestamp(), json().
Jebakan Umum
1. Mengedit migration yang sudah dijalankan. Migration yang sudah masuk tabel migrations tidak akan jalan lagi walau filenya diubah. Solusinya: buat migration baru untuk perubahannya (lihat modul migration-modifikasi), atau rollback dulu baru edit, baru migrate lagi.
2. Lupa menulis down(). Tanpa down() yang benar, migrate:rollback gagal membatalkan perubahan. Untuk Schema::create, pasangannya Schema::dropIfExists. Selalu tulis keduanya.
3. Mengubah database production manual. Godaan terbesar: "cuma tambah satu kolom, langsung via phpMyAdmin saja". Jangan. Perubahan itu tidak tercatat, tidak bisa diulang di server lain, dan tidak bisa di-rollback. Selalu lewat migration, tanpa kecuali.
Catatan teknis: Nama file migration harus unik dan berurutan berdasarkan timestamp. Kalau dua developer membuat migration di waktu yang sama persis, Laravel akan protes saat migrate. Di Laravel 11+, migration memakai anonymous class (
return new class extends Migration), jadi tidak ada lagi masalah nama class bentrok.
Tantangan
Tabel Kategori
Buat migration create_categories_table dengan kolom: id, name (string, unique), description (text, nullable), timestamps. Jalankan migrate dan verifikasi tabelnya via tinker (Schema::hasTable('categories')).