Laravel Seeder and Faker Tutorial: Populate Your Database with Dummy Data (Laravel 12 + PHP 8.3)

Categories: Backend Development

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 data
  • factory() 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() not make()?
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.