Laravel Seeder and Faker: Populating Your Database with Dummy Data
You’ve built migrations. Your tables exist.
Now comes the annoying part: getting meaningful test data into the database so you can actually build features.
Laravel solves this using:
- Seeders → control what data is inserted
- Factories + Faker → control how realistic data is generated
Let’s wire everything together properly using Laravel 12 + PHP 8.3 syntax.
Why Seeders Matter (Beyond Testing)
Seeders are not just for demo data.
Use them for:
- Initial admin users
- Default roles/permissions
- Lookup tables (countries, statuses)
- Generating bulk test records
- CI/CD automated setup
Key idea: Migrations define structure Seeders define initial content
Create a Seeder
Run:
php artisan make:seeder UserSeeder
This creates:
database/seeders/UserSeeder.php
Example:
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\User;
class UserSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
// Create a single known user (useful for login testing)
User::create([
'name' => 'Admin User',
'email' => 'admin@example.com',
'password' => bcrypt('password'), // Always hash passwords
]);
// Generate multiple random users using factory
User::factory()->count(10)->create();
}
}
Why this works
create()inserts fixed predictable datafactory()generates realistic randomized data- Mixing both gives you stable + random test data
Register Seeder in DatabaseSeeder
Open:
database/seeders/DatabaseSeeder.php
public function run(): void
{
$this->call([
UserSeeder::class,
]);
}
Why needed?
Laravel only executes DatabaseSeeder by default.
If you don’t register it here:
Seeder won’t run No error shown You’ll wonder why nothing happened
Run Seeders
Run all seeders:
php artisan db:seed
Run specific seeder:
php artisan db:seed --class=UserSeeder
Using Faker Through Factories
Laravel factories already include Faker automatically.
Create a factory:
php artisan make:factory PostFactory --model=Post
Open:
database/factories/PostFactory.php
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<\App\Models\Post>
*/
class PostFactory extends Factory
{
public function definition(): array
{
return [
// Faker generates realistic dummy values
'title' => fake()->sentence(),
'content' => fake()->paragraphs(3, true),
'published_at' => fake()->optional()->dateTime(),
];
}
}
Why fake() instead of $this->faker?
Laravel 10+ introduced the global helper:
fake()
Cleaner, shorter, and works perfectly in Laravel 12.
Use Factory Inside Seeder
use App\Models\Post;
public function run(): void
{
// Generate 50 posts
Post::factory()->count(50)->create();
}
Advanced Seeder Example (Relationships)
Let’s generate:
- 10 users
- each user → 5 posts
use App\Models\User;
use App\Models\Post;
public function run(): void
{
User::factory()
->count(10)
->create()
->each(function ($user) {
// Create posts linked to this user
Post::factory()
->count(5)
->create([
'user_id' => $user->id
]);
});
}
Why use each()?
Because you need access to the created user instance.
Factories alone can't automatically assign relationships unless configured.
Seeder Shortcuts for Fresh Database
Drop tables + migrate + seed
php artisan migrate:fresh --seed
Why useful?
- Perfect for resetting dev database
- Avoids manual delete/insert cycles
- Ensures reproducible environment
Common Errors & Fixes
Faker class not found
Cause: Using old syntax
$this->faker->name
Fix: Use Laravel 12 helper:
fake()->name()
MassAssignmentException
Cause: Missing $fillable in model
Fix:
protected $fillable = ['name','email','password'];
or temporarily:
Model::unguard();
(better avoid globally)
Seeder runs but inserts nothing
Check:
- Registered in DatabaseSeeder?
- Using
create()notmake()?
factory()->make() // creates object only in memory
factory()->create() // saves to database
SQL integrity constraint error
Usually means:
- foreign key missing
- wrong order of seeding
Fix:
Seed parent tables first.
$this->call([
UserSeeder::class,
PostSeeder::class,
]);
Duplicate entry for unique column
Fix with Faker unique:
'email' => fake()->unique()->safeEmail(),
Reset unique cache if needed:
fake()->unique(reset: true);
(PHP 8 named parameter supported)
Pro Tips for Production-Level Seeders
✔ Use environment checks
if (app()->environment('local')) {
User::factory(50)->create();
}
Avoid flooding production database.
✔ Seed lookup tables manually
DB::table('statuses')->insert([
['name' => 'draft'],
['name' => 'published'],
]);
Factories are overkill for fixed data.
Split seeders by domain
Good structure:
UserSeeder
RoleSeeder
PostSeeder
DemoContentSeeder
Cleaner CI pipelines and debugging.
Suggested Related Articles (Internal Linking)
- Laravel 12 Routing Tutorial (Practical Examples)
- Laravel Migration Best Practices
- Laravel Factories Deep Dive
- Laravel Testing with PHPUnit & Pest
- Optimizing Laravel Database Queries
Final Summary
Seeder = execution logic Factory = data blueprint Faker = realistic random generator
Together they let you:
- simulate production data
- test features faster
- onboard teammates easily
- automate database setup
Once you start using seeders properly, manually inserting rows in phpMyAdmin feels prehistoric.