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.