Reader Stacks

Creating and Running Database Seeders in Laravel

A factory generates realistic fake data at scale; a seeder decides what to actually create and in what order — the two are complementary tools, not interchangeable alternatives to each other.

Seeders populate the database with initial or test data — genuinely complementary to model factories (which generate realistic fake data at scale), since a seeder decides what to create and in what order, while a factory handles the actual data generation.

Generating a seeder

php artisan make:seeder ProductSeeder

A basic seeder using hardcoded data

class ProductSeeder extends Seeder
{
    public function run(): void
    {
        Product::create(['name' => 'Wireless Mouse', 'price' => 29.99]);
        Product::create(['name' => 'Mechanical Keyboard', 'price' => 89.99]);
    }
}

A seeder using a factory for bulk fake data

class ProductSeeder extends Seeder
{
    public function run(): void
    {
        Product::factory()->count(50)->create();
    }
}

Combining a seeder with a factory is the standard pattern for generating a realistic volume of test data — the factory (defined separately in database/factories/ProductFactory.php) handles what fake values each field gets, while the seeder simply decides how many to create and when.

Running a specific seeder

php artisan db:seed --class=ProductSeeder

Registering seeders in the main DatabaseSeeder

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

The order matters here — CategorySeeder runs before ProductSeeder deliberately, since products likely have a foreign key referencing categories; seeding a product before its referenced category exists would fail a foreign key constraint.

Running all registered seeders at once

php artisan db:seed

Combining migration and seeding in one command

php artisan migrate:fresh --seed

migrate:fresh drops every table and re-runs all migrations from scratch — combined with --seed, this rebuilds the entire database schema and repopulates it in one command, genuinely useful during active development when the schema itself is still changing frequently.

Seeding relationship data together

class OrderSeeder extends Seeder
{
    public function run(): void
    {
        Customer::factory()
            ->count(10)
            ->has(Order::factory()->count(3))
            ->create();
    }
}

Factory's has() method creates each customer along with a specified number of related orders in one chained call — this correctly wires up the foreign keys automatically, avoiding the need to manually create customers first and then loop through creating orders referencing each one's ID.

Why seeders should never run automatically against a production database

Seeders are meant for local development and testing environments — running a seeder containing hardcoded sample data (or, worse, migrate:fresh --seed, which drops every table) against a live production database would destroy real data; a genuine production data-population need calls for a dedicated, carefully reviewed Artisan command instead, never a standard development seeder run unguarded.