Understanding Laravel Factory States (Beginner-Friendly Guide)

When you’re working with Laravel, especially during testing or database seeding, you’ll often use factories to generate fake data. But sometimes, you don’t just want random data—you want specific types of data. That’s where factory states come in.

Let’s break it down in a simple way.

🧩 What is a Factory?

A factory in Laravel helps you create fake data for your database.

For example, instead of manually inserting records, you can do this:

Review::factory()->create();

This will generate a review with random values like rating, text, and timestamps.


🔄 The Problem

By default, factories generate completely random data.

But what if you want:

  • Only good reviews (rating 4–5)?
  • Only bad reviews (rating 1–2)?

You can’t control that easily with just the default factory.


✨ Solution: Factory States

A state is a way to customize or override certain fields in your factory.

Think of it as a preset version of your fake data.


🧪 Example

Default Factory

public function definition(): array
{
    return [
        'review' => $this->faker->paragraph,
        'rating' => $this->faker->numberBetween(1, 5),
    ];
}

This creates a review with a random rating between 1 and 5.


🌟 Adding a State

Now let’s create a good() state:

public function good()
{
    return $this->state(function () {
        return [
            'rating' => $this->faker->numberBetween(4, 5),
        ];
    });
}

This ensures that the rating is always 4 or 5.


🚀 How to Use It

Create a normal review:

Review::factory()->create();

Create a good review:

Review::factory()->good()->create();

Create multiple good reviews:

Review::factory()->good()->count(5)->create();

🧠 Why Use States?

Factory states help you:

  • Create specific test cases
  • Keep your code clean and reusable
  • Avoid repeating logic
  • Easily simulate real-world scenarios

🔥 Bonus: Another Example

You can create a bad() state too:

public function bad()
{
    return $this->state(fn () => [
        'rating' => $this->faker->numberBetween(1, 2),
    ]);
}

Now you can test both positive and negative cases easily.


✅ Final Thoughts

  • definition() → default random data
  • state() → customized version of that data

Once you start using factory states, your testing and seeding will become much more flexible and powerful.