Sitemap

Forget newFactory(): Use Laravel's UseFactory Attribute Like a Pro

4 min readMay 25, 2025
Forget newFactory(): Use Laravel's UseFactory Attribute Like a Pro

With Laravel constantly evolving to make development more expressive and maintainable, one of the latest features introduced in Laravel 10.37+ is the UseFactory attribute — a modern, PHP 8+ way to explicitly define model-to-factory relationships.

This article dives deep into how UseFactory simplifies factory usage in Laravel, especially in domain-driven or modular architectures, and how it can streamline your development experience.

🧱 The Problem with Traditional Factory Associations

Traditionally, Laravel relied on a convention-based approach to bind models with their factories. If you created a model named Article, you had to create a factory named ArticleFactory and place it in the database/factories directory. Laravel would then automatically find it using the HasFactory trait.

But what if your models live in custom namespaces like App\Domains\Content\Models? What if you follow a more modular or domain-driven design?

In those cases, you were required to manually override the newFactory() method on each model, like this:

use Database\Factories\ArticleFactory;

class Article extends Model
{
use HasFactory;

protected static function newFactory()
{
return ArticleFactory::new();
}
}

While this approach worked, it added boilerplate code and cluttered your model logic.

✨ Enter UseFactory: The Declarative Way

Laravel’s UseFactory attribute provides a cleaner, more elegant way to associate a factory with a model. It uses PHP attributes, introduced in PHP 8, to decorate your model with factory metadata.

✅ Basic Example

use Database\Factories\ArticleFactory;
use Illuminate\Database\Eloquent\Attributes\UseFactory;

#[UseFactory(ArticleFactory::class)]
class Article extends Model
{
use HasFactory;

protected $fillable = ['title', 'body', 'published_at'];
}

That’s it — no need for newFactory(), no guessing based on naming conventions. Just a clear, explicit declaration.

🧩 Works Seamlessly with Modular and DDD Architectures

If you’re building a Laravel application using Domain-Driven Design (DDD) or module-based architecture, your models might not reside in the default App\Models namespace. This is where UseFactory really shines.

Here’s an example from a modular project structure:

namespace App\Domains\Content\Models;

use Database\Factories\ArticleFactory;
use Illuminate\Database\Eloquent\Attributes\UseFactory;
use Illuminate\Database\Eloquent\Model;

#[UseFactory(ArticleFactory::class)]
class Article extends Model
{
use HasFactory;

protected $fillable = ['title', 'body', 'published_at'];
}

And another for a billing module:

namespace App\Domains\Billing\Models;

use Database\Factories\SubscriptionFactory;
use Illuminate\Database\Eloquent\Attributes\UseFactory;
use Illuminate\Database\Eloquent\Model;

#[UseFactory(SubscriptionFactory::class)]
class Subscription extends Model
{
use HasFactory;
}

This approach eliminates the need for repetitive newFactory() definitions and makes your code cleaner and easier to maintain.

🧠 Laravel’s Factory Resolution Logic

You might wonder: What happens if you define both the $factory static property and the UseFactory attribute?

Laravel resolves factories in the following priority:

  1. $factory static property (legacy style)
  2. #[UseFactory] attribute
  3. Convention-based resolution (e.g., ArticleFactory for Article)

This layered fallback ensures that your code won’t break existing factory logic and gives you flexibility to migrate incrementally.

🧑‍💻 Real-Life Example: Nested Relationships

The UseFactory attribute isn’t just for models — you can also use it with relationship methods to declare factories for related models.

use Illuminate\Database\Eloquent\Relations\HasMany;
use Database\Factories\CommentFactory;

#[UseFactory(ArticleFactory::class)]
class Article extends Model
{
use HasFactory;

#[UseFactory(CommentFactory::class)]
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}
}

While the above might not be used commonly, it shows Laravel’s potential direction for more expressive relationship metadata.

👩‍💻 Benefits of Using UseFactory

Code Clarity

Explicitly linking factories makes your code more self-documenting. When other developers read the model, they immediately know which factory it’s tied to.

✅ Less Boilerplate

No more overriding newFactory() in every custom-named model.

✅ IDE Support

Modern IDEs like PhpStorm or VS Code can now offer better autocomplete and navigation with attribute metadata.

✅ More Flexibility for Teams

In team environments, clear factory associations reduce confusion and onboarding time.

📸 Image Example

You can visualize a ProductVariant model in a domain-based folder like this:

namespace App\Modules\Inventory\Models;

use Illuminate\Database\Eloquent\Model;
use Database\Factories\ProductVariantFactory;
use Illuminate\Database\Eloquent\Attributes\UseFactory;

#[UseFactory(ProductVariantFactory::class)]
class ProductVariant extends Model
{
use HasFactory;

protected $fillable = ['sku', 'price', 'stock'];
}

This makes your factory usage consistent and discoverable even across deeply nested domain structures.

🧪 Testing with UseFactory

In your tests, the behavior stays the same:

use App\Domains\Content\Models\Article;

$article = Article::factory()->create();

$this->assertDatabaseHas('articles', [
'id' => $article->id,
]);

Since HasFactory automatically looks for the UseFactory attribute, you don’t need to do anything different in your tests.

🧭 Conclusion

The UseFactory attribute in Laravel is a small but powerful feature that brings modern PHP elegance to a common developer task. Whether you’re building a small app or a large-scale modular system, adopting this attribute can improve code clarity, reduce duplication, and help teams work more effectively.

So next time you’re creating a model in Laravel, try adding #[UseFactory(...)] instead of writing newFactory(). Your future self (and teammates) will thank you.

--

--

MasteryOfLaravel
MasteryOfLaravel

Written by MasteryOfLaravel

Laravel developer with over 13 years of experience. Writing to share advanced tips, real-world solutions, and backend mastery

No responses yet