Migration Laravel: Cara Membuat, Menjalankan, dan Rollback di Laravel 12

Migration Laravel adalah file PHP yang berisi perubahan struktur database, seperti membuat tabel, menambah kolom, atau memasang foreign key, sehingga perubahan itu tercatat di kode dan bisa dijalankan ulang di komputer mana pun. Buat migration dengan php artisan make:migration create_categories_table, lalu jalankan dengan php artisan migrate. Panduan ini membahas cara membuat migration di Laravel 12, tipe kolom yang sering dipakai, foreign key, mengubah kolom, dan semua perintah migrate (rollback, refresh, fresh, dan lainnya) beserta bedanya. Semua contoh sudah kami jalankan di Laravel 12.70.

Belum punya project? Mulai dari cara install Laravel 12. Urutan materi lengkap ada di halaman tutorial Laravel.

Kenapa Memakai Migration

Tanpa migration, struktur tabel biasanya dibuat lewat phpMyAdmin atau file SQL yang dikirim lewat chat. Masalahnya, sulit tahu tabel mana yang sudah diubah di laptop siapa, dan server production sering tertinggal. Dengan migration:

  • Setiap perubahan struktur tersimpan di folder database/migrations dan ikut masuk Git.
  • Rekan satu tim cukup menjalankan php artisan migrate untuk menyamakan struktur database.
  • Laravel mencatat migration yang sudah dijalankan di tabel migrations, jadi perintah yang sama tidak menjalankan file dua kali.
  • Perubahan bisa dibatalkan dengan migrate:rollback karena setiap file punya method down().

Ini juga jawaban untuk pertanyaan “cara memindahkan project Laravel ke laptop lain”: clone repository, jalankan composer install, siapkan .env, lalu php artisan migrate. Struktur tabel akan terbentuk sama persis.

Cara Membuat Migration di Laravel 12

php artisan make:migration create_categories_table

File baru muncul di database/migrations dengan nama berawalan waktu, misalnya 2026_10_19_052752_create_categories_table.php. Awalan waktu itu menentukan urutan eksekusi. Laravel juga menebak nama tabel dari nama migration: pola create_xxx_table menghasilkan kerangka Schema::create('xxx'), sedangkan pola seperti add_category_id_to_products_table menghasilkan kerangka Schema::table('products') untuk mengubah tabel yang sudah ada.

Migration juga bisa dibuat bersamaan dengan model:

php artisan make:model Category -mfs

Opsi -m membuat migration, -f factory, dan -s seeder. Daftar opsi lainnya ada di artikel perintah PHP Artisan.

Struktur file migration

<?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('categories', function (Blueprint $table) {
            $table->id();
            $table->string('name', 100);
            $table->string('slug')->unique();
            $table->text('description')->nullable();
            $table->boolean('is_active')->default(true);
            $table->timestamps();
        });
    }

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

Method up() dijalankan saat migrate, sedangkan down() saat rollback. Isi down() harus membatalkan apa yang dilakukan up(). Kalau up() membuat tabel, down() menghapusnya.

Tipe Kolom dan Modifier yang Sering Dipakai

Method Hasil
$table->id() Primary key id, big integer auto increment
$table->string('name', 100) VARCHAR, panjang bawaan 255
$table->text('description') Teks panjang
$table->integer('qty') / unsignedInteger / unsignedBigInteger Bilangan bulat
$table->decimal('weight', 8, 2) Desimal presisi tetap
$table->boolean('is_active') Benar/salah
$table->date('birth_date') / dateTime / timestamp Tanggal dan waktu
$table->json('meta') Data JSON
$table->enum('status', ['draft', 'published']) Pilihan terbatas
$table->foreignId('category_id') Kolom unsigned big integer untuk relasi
$table->timestamps() Kolom created_at dan updated_at
$table->softDeletes() Kolom deleted_at untuk soft delete

Modifier ditulis berantai setelah tipe kolom: ->nullable() (boleh kosong), ->default(0), ->unique(), ->index(), ->comment('...'), dan ->after('id') (posisi kolom, hanya berlaku di MySQL/MariaDB).

Untuk uang dalam rupiah, simpan sebagai bilangan bulat (unsignedBigInteger) daripada float. Float bisa menghasilkan selisih pembulatan.

Foreign Key dan Relasi Antar Tabel

Misalnya tabel products sudah ada dan ingin dihubungkan ke categories:

php artisan make:migration add_category_id_to_products_table
public function up(): void
{
    Schema::table('products', function (Blueprint $table) {
        $table->foreignId('category_id')
            ->nullable()
            ->after('id')
            ->constrained()
            ->nullOnDelete();
    });
}

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

constrained() otomatis menebak tabel tujuan dari nama kolom (category_id ke tabel categories, kolom id). Pilih aksi saat data induk dihapus:

  • ->cascadeOnDelete(): produk ikut terhapus saat kategorinya dihapus.
  • ->nullOnDelete(): category_id produk diisi NULL. Kolomnya harus nullable(). Kami menguji ini: setelah kategori dihapus, category_id produk berubah menjadi null.
  • ->restrictOnDelete(): kategori tidak bisa dihapus selama masih dipakai produk.

Urutan file penting. Migration tabel categories harus berjalan sebelum migration yang memasang foreign key ke tabel itu.

Menjalankan Migration: Semua Perintah dan Bedanya

Perintah Yang terjadi Data hilang?
php artisan migrate Menjalankan migration yang belum pernah dijalankan Tidak
php artisan migrate:status Menampilkan migration yang sudah (Ran) dan belum (Pending), beserta nomor batch Tidak
php artisan migrate --pretend Menampilkan query SQL tanpa menjalankannya Tidak
php artisan migrate:rollback Membatalkan batch terakhir (semua file yang dijalankan di migrate terakhir) Ya, untuk tabel/kolom yang di-rollback
php artisan migrate:rollback --step=1 Membatalkan satu file migration terakhir Ya, sebagian
php artisan migrate:reset Menjalankan down() semua migration Ya, semua
php artisan migrate:refresh Rollback semua lewat down(), lalu migrate lagi Ya, semua
php artisan migrate:fresh Menghapus semua tabel langsung (tanpa down()), lalu migrate lagi Ya, semua
php artisan migrate:fresh --seed Seperti di atas, lalu menjalankan seeder Ya, diganti data contoh

Beda migrate:refresh dan migrate:fresh: refresh memanggil down() setiap file satu per satu, sehingga ikut menguji apakah method down() kamu benar. fresh langsung menghapus semua tabel, jadi lebih cepat dan tetap jalan walaupun ada down() yang rusak. Keduanya menghapus semua data. Jangan pernah dijalankan di database production.

Menjalankan satu file migration saja

Pakai opsi --path dengan path file relatif dari root project:

php artisan migrate --path=database/migrations/2026_10_19_052753_add_category_id_to_products_table.php

Hanya file itu yang dijalankan, migration lain yang masih pending dibiarkan. Kalau file tersebut sudah pernah dijalankan, hasilnya Nothing to migrate.

Di server production

php artisan migrate --force

Di environment production, Laravel meminta konfirmasi sebelum menjalankan migration. --force melewati konfirmasi itu, biasanya dipakai di skrip deploy. Kalau aplikasi di-deploy ke beberapa server sekaligus, tambahkan --isolated agar migration tidak dijalankan dua server bersamaan.

Menjalankan migration dari kode

use Illuminate\Support\Facades\Artisan;

Artisan::call('migrate', ['--force' => true]);

Nilai kembalian 0 berarti berhasil. Cara ini kadang dipakai di installer aplikasi atau job deploy.

Mengubah, Mengganti Nama, dan Menghapus Kolom

Jangan mengedit file migration yang sudah dijalankan di server atau sudah dipakai rekan satu tim. Buat migration baru untuk setiap perubahan.

php artisan make:migration change_price_on_products_table
public function up(): void
{
    Schema::table('products', function (Blueprint $table) {
        $table->unsignedBigInteger('price')->default(0)->change();
    });
}

public function down(): void
{
    Schema::table('products', function (Blueprint $table) {
        $table->unsignedInteger('price')->change();
    });
}

Aturan penting dari dokumentasi Laravel: saat memakai change(), tulis ulang semua modifier yang ingin dipertahankan (nullable, default, unsigned, comment). Modifier yang tidak ditulis akan hilang. Sejak Laravel 11, change() tidak lagi butuh paket doctrine/dbal.

Mengganti nama dan menghapus kolom:

Schema::table('products', function (Blueprint $table) {
    $table->renameColumn('stock', 'quantity');
    $table->dropColumn(['old_code', 'notes']);
});

Error Migration yang Sering Muncul

  • Base table or view already exists. Tabelnya sudah dibuat manual atau dari migration lain, tetapi tidak tercatat di tabel migrations. Di lokal, cara tercepat adalah migrate:fresh. Di production, hapus atau ubah migration yang bentrok, jangan menghapus tabel berisi data.
  • Error foreign key saat migrate. Tabel tujuan belum ada karena urutan file salah, atau tipe kolomnya berbeda. Pakai foreignId() agar tipenya cocok dengan id().
  • SQLSTATE[HY000] [1045] Access denied atau could not find driver. Masalah koneksi, bukan migration. Cek DB_* di .env dan ekstensi pdo_mysql/pdo_sqlite. Panduan lengkapnya ada di artikel instalasi Laravel 12.
  • Rollback gagal. Method down() kosong atau tidak membalik up() dengan benar. Uji dengan migrate:refresh di lokal sebelum dipakai di server.
  • Perintah meminta konfirmasi lalu berhenti di skrip deploy. Environment-nya production. Tambahkan --force.

Pertanyaan yang Sering Diajukan

Bagaimana cara menjalankan satu migration tertentu?

Pakai php artisan migrate --path=database/migrations/nama_file.php. Untuk membatalkan satu migration terakhir, pakai php artisan migrate:rollback --step=1.

Apa beda migrate:fresh dan migrate:refresh?

migrate:refresh menjalankan down() setiap migration lalu migrate ulang. migrate:fresh langsung menghapus semua tabel lalu migrate ulang. Keduanya menghapus semua data.

Apakah boleh mengedit file migration lama?

Boleh hanya kalau migration itu belum pernah dijalankan di tempat lain selain laptop kamu. Kalau sudah ada di server atau dipakai tim, buat migration baru.

Apa itu database migration secara umum?

Istilah ini punya dua arti. Di Laravel, migration berarti versi struktur database dalam bentuk kode. Di luar konteks framework, “migrasi data” juga bisa berarti memindahkan data dari satu sistem ke sistem lain, yang merupakan pekerjaan berbeda.

Setelah tabel siap, hubungkan ke URL lewat route Laravel dan logika CRUD di controller Laravel 12. Kalau database kamu PostgreSQL, lihat juga tutorial PostgreSQL di Laravel.

Perlu memindahkan data dari sistem lama atau Excel ke aplikasi Laravel baru? Tim Arrazy Inovasi di Purwokerto mengerjakan pembuatan sistem aplikasi custom, termasuk perancangan database dan migrasi datanya.

Diskusikan project kamu →

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *