Laravel factories and seeders: what each one does
Use factories to define model data and seeders to organize database population, with clear boundaries for test records and production reference data.
A factory defines how to generate a model's attributes and related data. A seeder decides what a database should contain and coordinates the inserts. They work well together: a seeder can call factories to populate a realistic test dataset.
Factories define model data
This class-body example assumes the normal factory namespace and imports, a User model with HasFactory, and a matching schema. Fixed example passwords belong only in isolated test data.
class UserFactory extends Factory
{
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'password' => bcrypt('password'),
];
}
}
Typical calls include:
User::factory()->count(50)->create();
User::factory()->hasPosts(3)->create();
User::factory()->make();
create() persists models. make() returns an unsaved model, though associated factories or callbacks can still perform database work; do not assume every factory composition is entirely database-free. hasPosts(3) relies on the corresponding relationship and factory and, in this call, creates one user with three posts.
Factories support bulk generation, relationships such as for(User::factory()), and states such as state(['role' => 'admin']) when that field exists. States describe test scenarios; they are not an authorization or production account-provisioning mechanism.
Seeders organize population
Seeder classes live in database/seeders. The default entry point is DatabaseSeeder; its call() method invokes other seeders in order.
The following class body assumes imports for Seeder, DB, and User, and existing product and order seeders. Run this mixed reference-data and fake-data example only in a disposable environment:
class DatabaseSeeder extends Seeder
{
public function run(): void
{
if (! app()->environment(['local', 'testing'])) {
throw new \RuntimeException('Demo data requires local/testing');
}
DB::table('roles')->insert([
['name' => 'admin'],
['name' => 'user'],
]);
User::factory()->count(50)->hasPosts(1)->create();
$this->call([
ProductSeeder::class,
OrderSeeder::class,
]);
}
}
Run the default or a selected seeder:
php artisan db:seed
php artisan db:seed --class=ProductSeeder
# Destructive: only for a confirmed disposable database.
php artisan migrate:fresh --seed
The last command drops every table on the target connection before rebuilding. The plain insert example is also not idempotent: repeated runs can duplicate rows or violate a unique constraint.
Compare their roles
| Concern | Factory | Seeder |
|---|---|---|
| Main responsibility | Define model attributes, states, and relationships | Decide what to populate and in which order |
| Fake data | Commonly uses Faker | Can call factories or use explicit values |
| Relationships | Composes related factories | Coordinates prerequisites or inserts manually |
| Typical use | Tests and realistic development records | Reference data, fixtures, and demo datasets |
| Entry point | Called from tests, seeders, or application tooling | php artisan db:seed |
For production reference data, use reviewed, repeatable seeders with unique constraints and appropriate upserts. Keep fake data separate. Production seeding is supported, but --force only bypasses confirmation; it does not make a seeder safe.
Common questions
Can Faker generate Chinese names and addresses? Set the application's Faker locale to zh_CN in the relevant Laravel configuration. This changes generated fixture data, not the application's interface language. Review the available providers and fields for that locale.
Why does factory(App\User::class, 50) fail after an upgrade? That is the older function-based API used before Laravel 8's class-based factories. Migrate factory definitions and add the appropriate HasFactory support, then use User::factory()->count(50)->create().
References: Laravel factories and seeding. These examples use class-based factories; verify compatibility with your installed framework version.
Related reading
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan