Lessons → Laravel Framework → Lesson 11

Seeders & Factories

Laravel
⏱ 20 min read⚡ IntermediateNot completed

Seeders populate your database with data. Factories generate fake model instances. Together they let you set up a realistic development environment and write tests without manually inserting rows.

How They Work Together

ToolPurposeUsed For
FactoryGenerates fake model dataTests, seeders, quick prototyping
SeederRuns insert logic against the DBDev setup, demo data, initial records
FakerProvides fake data valuesInside factories (names, emails, etc.)

1. Creating a Factory

Terminal
# Generate a factory for the User model
php artisan make:factory UserFactory --model=User

# Generate a factory for a Post model
php artisan make:factory PostFactory --model=Post
database/factories/PostFactory.php
<?php

namespace Database\Factories;

use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;

class PostFactory extends Factory
{
    public function definition(): array
    {
        return [
            'user_id'    => User::factory(),
            'title'      => fake()->sentence(6),
            'slug'       => fake()->unique()->slug(),
            'body'       => fake()->paragraphs(4, true),
            'status'     => fake()->randomElement(['draft', 'published']),
            'published_at' => fake()->optional()->dateTimeBetween('-1 year', 'now'),
        ];
    }
}

2. Useful Faker Methods

Faker methodExample output
fake()->name()Jane Smith
fake()->email()user@example.com
fake()->sentence(5)The quick brown fox jumps.
fake()->paragraphs(3, true)Multi-paragraph string
fake()->numberBetween(1, 100)42
fake()->randomElement(['a','b'])a or b
fake()->unique()->slug()lorem-ipsum-dolor (unique)
fake()->optional()Value or null (70/30 chance)
fake()->dateTimeBetween('-1 year', 'now')A DateTime object
fake()->imageUrl(640, 480)https://via.placeholder.com/...

3. Factory States

States let you define named variations of a factory:

database/factories/PostFactory.php
public function definition(): array
{
    return [
        'title'  => fake()->sentence(),
        'status' => 'draft',
    ];
}

public function published(): static
{
    return $this->state(fn (array $attrs) => [
        'status'       => 'published',
        'published_at' => now(),
    ]);
}

public function withLongTitle(): static
{
    return $this->state(fn (array $attrs) => [
        'title' => fake()->sentence(20),
    ]);
}
Using States
// Draft post (default)
Post::factory()->create();

// Published post
Post::factory()->published()->create();

// Published post with long title
Post::factory()->published()->withLongTitle()->create();

4. Creating a Seeder

Terminal
php artisan make:seeder PostSeeder
database/seeders/PostSeeder.php
<?php

namespace Database\Seeders;

use App\Models\Post;
use App\Models\User;
use Illuminate\Database\Seeder;

class PostSeeder extends Seeder
{
    public function run(): void
    {
        // Create 5 users, each with 10 posts
        User::factory(5)->create()->each(function (User $user) {
            Post::factory(10)->create(['user_id' => $user->id]);
        });

        // Create 3 published posts specifically
        Post::factory(3)->published()->create();
    }
}

5. DatabaseSeeder — the Entry Point

database/seeders/DatabaseSeeder.php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

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

6. Running Seeders

Terminal
# Run all seeders (DatabaseSeeder)
php artisan db:seed

# Run a specific seeder
php artisan db:seed --class=PostSeeder

# Fresh migration + seed in one command
php artisan migrate:fresh --seed

7. Using Factories in Tests

Factories are most powerful in tests — no manual DB setup needed:

tests/Feature/PostTest.php
<?php

namespace Tests\Feature;

use App\Models\Post;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PostTest extends TestCase
{
    use RefreshDatabase;

    public function test_user_can_view_published_posts(): void
    {
        // Create 3 published and 2 draft posts
        Post::factory(3)->published()->create();
        Post::factory(2)->create(); // draft

        $response = $this->getJson('/api/posts');

        $response->assertOk()
                 ->assertJsonCount(3, 'data');
    }

    public function test_authenticated_user_can_create_post(): void
    {
        $user = User::factory()->create();

        $this->actingAs($user)->postJson('/api/posts', [
            'title' => 'My Post',
            'body'  => 'Some content here.',
        ])->assertCreated();

        $this->assertDatabaseHas('posts', ['title' => 'My Post']);
    }
}

8. Factory Relationships

Creating Related Models
// Create a post with its author auto-created
$post = Post::factory()->create();

// Create a post belonging to a specific user
$user = User::factory()->create();
$post = Post::factory()->create(['user_id' => $user->id]);

// Create a user with 5 posts using has()
$user = User::factory()
            ->has(Post::factory()->count(5), 'posts')
            ->create();

// Create posts with their author using for()
$posts = Post::factory(10)
             ->for(User::factory()->create(), 'author')
             ->create();
💡
RefreshDatabase in tests. Always add use RefreshDatabase; to test classes that hit the database — it wraps each test in a transaction and rolls it back, keeping tests isolated and fast.
⚠️
Never run seeders in production with fake data. Use --env=local or guard your seeders with an environment check: if (app()->isProduction()) return;
← Previous Lesson All Lessons →
🧠

Test your knowledge!

Take the Laravel quiz.

Take Quiz →