Skema yang rapi tetap kosong tanpa data. Aplikasi nyata hampir selalu butuh data awal: akun administrator, daftar kategori, provinsi, atau jenis pembayaran — data yang harus ada sebelum pengguna pertama mendaftar. Database seeder adalah class PHP yang mengisi tabel lewat kode, sehingga data awal ikut tersimpan di repositori Git, bisa ditinjau lewat code review, dan dijalankan ulang kapan pun oleh anggota tim. Chapter ini membahas anatomi seeder, cara menjalankannya dengan db:seed, serta pola migrate:fresh --seed yang menjadi perintah sehari-hari selama pengembangan.

Anatomi DatabaseSeeder #

Semua seeder tersimpan di database/seeders/ dan berawal dari satu class bawaan bernama DatabaseSeeder. Class ini adalah pintu masuk sekaligus penyusun urutan: method run() di dalamnya memanggil seeder lain lewat $this->call(). Berikut isi lengkapnya setelah kita isi:

php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        $this->call([
            UserSeeder::class,
            TaskSeeder::class,
        ]);
    }
}

Array pada $this->call() dijalankan berurutan dari atas ke bawah, jadi urutan penting bila satu seeder bergantung pada hasil seeder sebelumnya — pengguna harus ada lebih dulu sebelum tugas yang menunjuknya disisipkan.

Membuat Seeder Baru #

Seeder baru dibuat lewat artisan, sama seperti migration. Kita butuh dua seeder, satu untuk data master dan satu untuk contoh data awal:

bash
php artisan make:seeder UserSeeder
php artisan make:seeder TaskSeeder

Output yang Dihasilkan:

text
   INFO  Seeder [database/seeders/UserSeeder.php] created successfully.  

   INFO  Seeder [database/seeders/TaskSeeder.php] created successfully.  

Kedua berkas berisi class kosong dengan satu method run(). Kita isi UserSeeder dengan akun awal lewat model User:

php
<?php

namespace Database\Seeders;

use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;

class UserSeeder extends Seeder
{
    public function run(): void
    {
        User::create([
            'name' => 'Budi',
            'email' => '[email protected]',
            'password' => Hash::make('password-rahasia'),
        ]);
    }
}

Pemakaian model User di sini disengaja: password melewati Hash::make() sehingga tersimpan ter-hash, persis seperti alur pendaftaran normal. Untuk baris-baris sederhana, query builder juga memadai — TaskSeeder mengisi tiga tugas sekaligus lewat satu pernyataan insert():

php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class TaskSeeder extends Seeder
{
    public function run(): void
    {
        $waktu = '2026-01-05 08:00:00';

        DB::table('tasks')->insert([
            ['user_id' => 1, 'judul' => 'Belajar seeding Laravel', 'slug' => 'belajar-seeding-laravel', 'status' => 'selesai', 'created_at' => $waktu, 'updated_at' => $waktu],
            ['user_id' => 1, 'judul' => 'Menulis migration baru', 'slug' => 'menulis-migration-baru', 'status' => 'proses', 'created_at' => $waktu, 'updated_at' => $waktu],
            ['user_id' => 1, 'judul' => 'Review skema database', 'slug' => 'review-skema-database', 'status' => 'todo', 'created_at' => $waktu, 'updated_at' => $waktu],
        ]);
    }
}

Menjalankan db:seed #

Perintah db:seed menjalankan DatabaseSeeder, yang selanjutnya memanggil kedua seeder anak:

bash
php artisan db:seed

Output yang Dihasilkan:

text
   INFO  Seeding database.  

  Database\Seeders\UserSeeder ........................................ RUNNING  
  Database\Seeders\UserSeeder .................................... 224 ms DONE  

  Database\Seeders\TaskSeeder ........................................ RUNNING  
  Database\Seeders\TaskSeeder ...................................... 0 ms DONE  

Apa yang terjadi bila perintah yang sama dijalankan dua kali? Seeder kita tidak dirancang idempotent, dan constraint dari chapter Foreign Keys langsung menampik:

text
   INFO  Seeding database.  

  Database\Seeders\UserSeeder ........................................ RUNNING  

   Illuminate\Database\UniqueConstraintViolationException 

  SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: users.email (Connection: sqlite, ...)

Email [email protected] sudah ada, jadi User::create() yang kedua gagal. Bila seeder perlu aman diulang, gunakan User::firstOrCreate([...]) atau insertOrIgnore() alih-alih create() dan insert() biasa.

Menjalankan Seeder Tunggal #

Kadang kita hanya perlu menjalankan satu seeder tanpa menyentuh yang lain — misalnya setelah menambah seeder kategori baru di proyek yang datanya sudah terisi. Opsi --class memilih class tertentu:

bash
php artisan db:seed --class=TaskSeeder

Output yang Dihasilkan:

text
   INFO  Seeding database.  

  Database\Seeders\TaskSeeder ........................................ RUNNING  
  Database\Seeders\TaskSeeder ...................................... 8 ms DONE  

Hanya TaskSeeder yang berjalan — DatabaseSeeder beserta UserSeeder tidak tersentuh. Fitur ini juga menjadi fondasi seeder produksi yang terstruktur: setiap seeder bisa dijalankan terpisah sesuai kebutuhan tanpa mengulang data master.

migrate:fresh --seed: Perintah Sehari-hari #

Selama pengembangan, kombinasi yang paling sering dipakai adalah membangun ulang seluruh database dari nol lalu mengisinya — satu perintah, urut, dan hasilnya selalu sama:

bash
php artisan migrate:fresh --seed

Output yang Dihasilkan:

text
  Dropping all tables ............................................ 3.19ms DONE

   INFO  Preparing database.  

  Creating migration table ....................................... 2.52ms DONE

   INFO  Running migrations.  

  0001_01_01_000000_create_users_table ........................... 1.88ms DONE
  0001_01_01_000001_create_cache_table ........................... 0.84ms DONE
  0001_01_01_000002_create_jobs_table ............................ 1.61ms DONE
  2026_10_13_153049_create_personal_access_tokens_table .......... 0.80ms DONE
  2026_10_13_170012_create_posts_table ........................... 0.71ms DONE
  2026_10_13_170036_create_products_table ........................ 0.54ms DONE
  2026_10_13_170109_create_tasks_table ........................... 0.72ms DONE
  2026_10_13_170140_create_comments_table ........................ 2.60ms DONE


   INFO  Seeding database.  

  Database\Seeders\UserSeeder ........................................ RUNNING  
  Database\Seeders\UserSeeder .................................... 214 ms DONE  

  Database\Seeders\TaskSeeder ........................................ RUNNING  
  Database\Seeders\TaskSeeder ...................................... 0 ms DONE  

Skema dijatuhkan, dibangun ulang migration demi migration, lalu seeder mengisinya — database lokal selalu berada di keadaan yang bisa diprediksi. Kebiasaan ini juga aman untuk demo dan pengujian otomatis, karena setiap orang mendapat data yang identik.

Seeder sangat cocok untuk data yang nilainya tetap dan jumlahnya sedikit. Begitu kita butuh puluhan data uji yang bervariasi untuk menguji pagination atau tampilan daftar, menulis baris satu per satu tidak lagi praktis — di situlah model factories berperan, topik chapter berikutnya. Daftar lengkap kemampuan seeder, termasuk memanggil seeder dari seeder lain dengan parameter, tersedia di dokumentasi seeding .