Migration

Schema builder, tipe kolom, dan rollback untuk mengelola skema database.

Daftar isi

Migration adalah mekanisme Laravel untuk mengelola perubahan skema database dalam bentuk berkas PHP yang berurutan. Topik ini membahas cara membuat berkas migration dengan Artisan, menulis definisi tabel menggunakan schema builder, menjalankan serta membatalkan migration, dan memeriksa hasilnya. Seluruh contoh diterapkan pada aplikasi catatan sehingga di akhir topik dua tabel inti, yaitu categories dan notes, sudah terbentuk dan siap digunakan oleh model Eloquent.

Migration sebagai riwayat skema#

Skema database sering berubah selama aplikasi dikembangkan: tabel ditambah, kolom disesuaikan, dan indeks dilengkapi. Apabila perubahan hanya ditulis sebagai SQL manual, setiap anggota tim dan setiap lingkungan harus menyalinnya dengan tangan, sehingga struktur database mudah menjadi tidak sinkron. Migration menyelesaikan masalah tersebut dengan menyimpan setiap perubahan skema sebagai satu berkas PHP di dalam direktori database/migrations, lalu mengeksekusi berkas-berkas itu berurutan sesuai waktu pembuatannya.

Setiap berkas migration memuat dua metode. Metode up() mendefinisikan perubahan yang ingin diterapkan, misalnya membuat tabel baru, sedangkan metode down() membalik perubahan tersebut, misalnya menjatuhkan tabel itu kembali. Laravel mencatat migration mana yang sudah dieksekusi pada tabel khusus bernama migrations di dalam database. Catatan tersebut membuat perintah migrate dapat dipanggil berulang kali tanpa risiko: hanya migration yang belum dijalankan yang dieksekusi, sedangkan migration lama dibiarkan apa adanya.

Membuat berkas migration#

Berkas migration dibuat dengan perintah make:migration. Apabila nama berkas dimulai dengan create_ dan diakhiri _table, Artisan menghasilkan kerangka Schema::create, sehingga berkasnya langsung siap diisi.

bash
# tidak-dijalankan
# membuat dua berkas migration untuk tabel kategori dan catatan
cd ~/aplikasi-catatan
php artisan make:migration create_categories_table
php artisan make:migration create_notes_table

Perintah tersebut tidak dieksekusi pada contoh ini karena berkasnya sudah dibuat sebelumnya. Keluaran asli dari perintah itu adalah sebagai berikut.

text Hasil perintah make:migration

   INFO  Migration [database/migrations/2026_11_03_002752_create_categories_table.php] created successfully.  

   INFO  Migration [database/migrations/2026_11_03_002753_create_notes_table.php] created successfully.  

Nama berkas diawali waktu pembuatan, sehingga nilainya berbeda pada setiap lingkungan. Awalan waktu itulah yang menentukan urutan eksekusi antar-berkas: migration categories yang dibuat lebih dahulu dijalankan sebelum migration notes yang merujuk kepadanya.

Isi metode up() ditulis dengan schema builder, yaitu kumpulan metode pada kelas Blueprint yang menerjemahkan pemanggilan berantai menjadi pernyataan CREATE TABLE. Definisi tabel kategori terdiri atas kolom id bertipe auto increment, kolom nama, serta dua kolom waktu bawaan.

php create_categories_table.php
// tidak-dijalankan
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->id();
            $table->string('nama');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('categories');
    }
};

Tabel catatan memuat judul dan isi, ditambah kolom category_id yang menghubungkan setiap catatan dengan kategorinya. Metode foreignId() membuat kolom bertipe integer yang cocok dengan id milik tabel lain, sedangkan nullable() memperbolehkan catatan tanpa kategori dan constrained() menambahkan foreign key yang merujuk ke tabel categories.

php create_notes_table.php
// tidak-dijalankan
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('notes', function (Blueprint $table) {
            $table->id();
            $table->string('judul');
            $table->text('isi');
            $table->foreignId('category_id')->nullable()->constrained();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('notes');
    }
};

Beberapa tipe kolom yang paling sering digunakan dirangkum pada tabel berikut, dan selengkapnya tercantum pada dokumentasi migration Laravel.

MetodeHasil di databaseKegunaan
id()integer, auto increment, primary keyKunci utama tabel
string('nama')varcharTeks pendek seperti nama atau judul
text('isi')textTeks panjang seperti isi catatan
foreignId('category_id')integer, unsignedKolom penghubung antartabel
boolean('aktif')tinyintNilai benar atau salah
timestamps()dua kolom datetimeWaktu dibuat dan diperbarui

Menjalankan migration#

Perintah migrate mengeksekusi seluruh migration yang belum tercatat pada tabel migrations. Perintah ini bersifat idempoten: apabila tidak ada migration baru, tidak ada yang dijalankan.

bash
# mengeksekusi seluruh migration yang belum dijalankan
cd ~/aplikasi-catatan
php artisan migrate
text Keluaran
   INFO  Nothing to migrate.

Keluaran di atas diambil dari lingkungan contoh yang seluruh migrationnya sudah pernah dieksekusi. Pada eksekusi pertama, perintah yang sama mencantumkan setiap berkas beserta lamanya. Keluaran berikut diambil saat migration contoh ini pertama kali dijalankan.

text Hasil migrate pada eksekusi pertama
   INFO  Running migrations.

  2026_11_03_003023_create_categories_table ...................... 1.73ms DONE
  2026_11_03_003024_create_notes_table ........................... 0.93ms DONE

Struktur tabel hasil migration dapat diperiksa tanpa membuka aplikasi database. Perintah db:table menampilkan daftar kolom, tipe datanya, dan kunci asing dari sebuah tabel.

bash
# memeriksa struktur tabel notes hasil migration
cd ~/aplikasi-catatan
php artisan db:table notes
text Keluaran

  main.notes .................................................................  
  Columns .................................................................. 6  

  Column ................................................................ Type  
  id integer, autoincrement .......................................... integer  
  judul varchar ...................................................... varchar  
  isi text .............................................................. text  
  category_id integer, nullable ...................................... integer  
  created_at datetime, nullable ..................................... datetime  
  updated_at datetime, nullable ..................................... datetime  

  Index ......................................................................  
  primary id ......................................................... primary  

  Foreign Key .......................................... On Update / On Delete  
  category_id references id on categories .............. no action / no action  

Daftar migration beserta statusnya juga dapat dilihat kapan saja. Contoh berikut membangun ulang skema lebih dahulu dengan migrate:fresh agar seluruh migration dieksekusi pada satu batch yang sama dan daftarnya selalu sama. Status Ran berarti migration sudah dieksekusi, sedangkan Pending berarti belum.

bash
# melihat daftar migration beserta statusnya
cd ~/aplikasi-catatan
# bangun ulang skema dari awal; keluarannya tidak diperlukan
php artisan migrate:fresh --force > /dev/null
# tampilkan daftar migration beserta statusnya
php artisan migrate:status
text Keluaran
  Migration name .............................................. Batch / Status  
  0001_01_01_000000_create_users_table ............................... [1] Ran  
  0001_01_01_000001_create_cache_table ............................... [1] Ran  
  0001_01_01_000002_create_jobs_table ................................ [1] Ran  
  2026_11_03_003023_create_categories_table .......................... [1] Ran  
  2026_11_03_003024_create_notes_table ............................... [1] Ran  
  2026_11_03_085521_create_notifications_table ....................... [1] Ran  
  2026_11_03_212653_create_personal_access_tokens_table .............. [1] Ran  

Tujuh baris di atas mencakup seluruh migration proyek contoh: tiga migration bawaan Laravel untuk tabel users, cache, dan jobs, dua migration aplikasi catatan untuk tabel categories dan notes, ditambah migration notifications untuk fitur notifikasi dan personal_access_tokens untuk token API yang digunakan contoh API pada jalur ini. Seluruhnya berstatus Ran pada batch [1] karena migrate:fresh menjatuhkan semua tabel lalu mengeksekusi setiap migration sekali jalan.

Membatalkan migration#

Metode down() digunakan oleh perintah migrate:rollback, yang membatalkan migration pada batch terakhir dengan menjatuhkan tabel yang baru dibuat. Perintah ini berguna ketika definisi tabel ternyata keliru dan perlu ditulis ulang dari awal.

bash
# tidak-dijalankan
# membatalkan batch migration terakhir
cd ~/aplikasi-catatan
php artisan migrate:rollback

Perintah di atas tidak dieksekusi pada contoh ini karena menjatuhkan tabel dan datanya. Gunakan rollback hanya pada masa pengembangan, misalnya sebelum data nyata mulai disimpan. Setelah tabel dijatuhkan, perbaiki isi migration lalu jalankan kembali php artisan migrate untuk membangun ulang skemanya.

Kesalahan umum#

Kesalahan pertama adalah mengubah isi migration yang sudah dieksekusi dan menganggap perubahan langsung muncul pada skema. Tabel migrations tetap mencatat berkas itu sebagai selesai, sehingga Laravel tidak menjalankannya lagi. Solusinya, jalankan migrate:rollback, perbaiki berkasnya, lalu jalankan kembali migrate pada lingkungan pengembangan, atau buat migration baru untuk mengubah struktur pada lingkungan yang datanya tidak boleh hilang.

Kesalahan kedua adalah membuat migration notes lebih dulu daripada categories. Foreign key pada tabel notes merujuk ke tabel categories, sehingga eksekusi gagal dengan pesan bahwa tabel yang dirujuk tidak ada. Urutkan pembuatan berkas sesuai ketergantungan tabelnya.

Kesalahan ketiga adalah menjalankan rollback di lingkungan yang berisi data penting. Perintah itu menjatuhkan tabel tanpa konfirmasi lanjutan, sehingga datanya ikut hilang. Cadangkan database sebelum membatalkan migration, atau tulis migration baru yang mengubah struktur tanpa menjatuhkan tabel.

Ringkasan#

  • Migration menyimpan perubahan skema sebagai berkas PHP berurutan di database/migrations, dengan metode up() untuk menerapkan dan down() untuk membalik perubahan.
  • Schema builder menerjemahkan metode seperti id(), string(), text(), foreignId(), dan timestamps() menjadi pernyataan CREATE TABLE.
  • php artisan migrate idempoten: hanya migration yang belum tercatat yang dieksekusi, dan catatannya disimpan pada tabel migrations.
  • Struktur hasil migration dapat diperiksa dengan db:table dan riwayatnya dengan migrate:status, sedangkan migrate:rollback membatalkan batch terakhir.

Referensi#