Skema database tidak pernah selesai pada hari pertama. Sepanjang umur aplikasi, kita menambah kolom, mengganti tipe data, membuat tabel baru, dan menghapus yang tidak terpakai. Cara paling naif menghadapinya adalah menjalankan ALTER TABLE langsung — lewat klien database atau tombol GUI — setiap kali kebutuhan muncul. Pendekatan itu bisa lolos saat mengerjakan proyek sendirian, tetapi runtuh begitu aplikasi dikerjakan beramai-ramai. Migration adalah jawaban Laravel untuk masalah ini, dan sebelum menulis migration pertama kita, penting memahami masalah apa persisnya yang diselesaikannya.
Masalah Perubahan Skema Manual #
Bayangkan Budi dan Siti mengerjakan aplikasi blog yang sama. Budi menambahkan kolom excerpt pada tabel posts di mesinnya lewat klien database, lalu menulis kode yang membaca kolom tersebut. Siti menarik kode terbaru dari Git dan mendapati aplikasinya gagal — database di mesinnya tidak punya kolom excerpt. Masalah seperti ini muncul dari tiga sifat perubahan skema manual:
- Skema setiap anggota tim menyimpang — perubahan hanya hidup di database mesin Budi; tidak ada mekanisme otomatis yang menyampaikannya ke database Siti.
- Tidak ada riwayat — pertanyaan “kolom ini ditambah kapan dan kenapa” tidak punya jawaban, karena
ALTER TABLEyang dijalankan manual tidak terdokumentasi di mana pun. - Database baru tidak bisa direproduksi — membangun ulang database untuk server staging atau anggota tim baru harus dilakukan dengan mengingat-ingat seluruh perubahan sejak awal, dan satu saja tertinggal maka skema tidak konsisten.
Akar masalahnya satu: skema database hidup di luar sistem version control, sementara kode aplikasi hidup di dalamnya.
Migration sebagai Version Control untuk Skema #
Migration memindahkan perubahan skema ke dalam berkas PHP yang disimpan di direktori database/migrations. Satu berkas migration mendeskripsikan satu perubahan melalui dua method yang saling berkebalikan: up() menerapkan perubahan (membuat tabel, menambah kolom), sedangkan down() membatalkannya (menghapus tabel, membuang kolom). Karena berkas ini ikut di-commit ke repositori Git, skema database memperoleh apa yang selama ini hanya dimiliki kode: riwayat yang bisa dilihat, di-review, dan dijalankan ulang oleh siapa pun.
Urutan eksekusinya dijamin oleh nama berkas yang diawali timestamp — misalnya 2026_10_13_170046_create_posts_table berarti dibuat pada tanggal 13 Oktober 2026 pukul 17:00:46. Setiap kali seorang anggota tim menjalankan php artisan migrate, Laravel menjalankan semua berkas yang belum pernah dijalankan di database miliknya, sesuai urutan waktu pada nama berkas.
Tabel migrations sebagai Buku Besar #
Bagaimana Laravel tahu migration mana yang sudah dijalankan? Jawabannya: Laravel mencatatnya di database itu sendiri, pada tabel bernama migrations (namanya bisa diganti lewat blok migrations di config/database.php). Berikut isi tabel tersebut pada proyek latihan kita:
0001_01_01_000000_create_users_table batch 1
0001_01_01_000001_create_cache_table batch 1
0001_01_01_000002_create_jobs_table batch 1
2026_10_13_153049_create_personal_access_tokens_table batch 1
2026_10_13_170046_create_posts_table batch 1
2026_10_13_170257_add_excerpt_to_posts_table batch 2
2026_10_13_170304_rename_body_to_content_in_posts_table batch 2Sebelum menjalankan migrate, Laravel membandingkan daftar berkas di database/migrations dengan baris-baris di tabel ini. Hanya berkas yang namanya belum tercatat yang dijalankan — itulah sebabnya menjalankan migrate dua kali berturut-turut aman: eksekusi kedua tidak menemukan pekerjaan baru.
Konsep Batch #
Kolom kedua pada tabel di atas adalah nomor batch. Setiap kali perintah migrate menjalankan satu atau beberapa migration, seluruhnya dicatat dengan nomor batch yang sama — nomor batch tertinggi yang sudah ada ditambah satu. Pada contoh di atas, kelima migration pertama berjalan lewat satu perintah (batch 1), sedangkan dua migration perubahan kolom berjalan lewat perintah berikutnya (batch 2). Batch penting karena menjadi satuan pembatalan: migrate:rollback membatalkan seluruh migration pada batch terakhir sekaligus. Perilaku ini akan kita praktikkan tuntas pada chapter Migration Rollback.
Alur Kerja Tim dengan Migration #
Dengan semua mekanisme tersebut, alur kerja tim menjadi deterministik. Diagram berikut menampilkan siklus lengkapnya dari satu perubahan skema sampai produksi:
Tidak ada lagi langkah “ingat-ingat perubahan apa saja” — perintah migrate yang sama, dijalankan di mana pun, selalu membawa database ke struktur terbaru. Server produksi tidak berbeda: deployment aplikasi Laravel lazimnya selalu diakhiri satu perintah migrate.
Teorinya cukup. Pada chapter berikutnya kita praktik membuat migration pertama milik kita sendiri — tabel posts untuk aplikasi blog — mulai dari perintah make:migration sampai menjalankannya.