Understanding Laravel Eloquent Model Attributes (With Real Examples)

Understanding Laravel Eloquent Model Attributes (With Real Examples)

January 10, 2026
53 views

Laravel has quietly introduced a set of PHP attributes that make Eloquent models more explicit, readable, and discoverable. These live under Illuminate\Database\Eloquent\Attributes, but many developers either don’t know they exist or aren’t sure when to use them.

In this article, we’ll walk through what Eloquent model attributes are, what each one does, and how to use them with real examples—beyond what’s shown in the docs.

What are Eloquent Model Attributes?

Eloquent model attributes are PHP 8 Attributes that let you declare model behavior directly on the model class itself.

Instead of relying on naming conventions, service provider registration, or hidden boot logic, these attributes make relationships and behaviour explicit and self-contained.

They don't replace Eloquent fundamentals — but they do improve clarity, especially in larger or long-lived codebases.

#[Boot] — Defining model boot logic explicitly

The #[Boot] attribute marks a static method as a model boot method.

Before:

protected static function booted()
{
    static::creating(function ($model) {
        // ...
    });
}

With #[Boot]:

use Illuminate\Database\Eloquent\Attributes\Boot;

#[Boot]
public static function booting()
{
    static::creating(function ($model) {
        // ...
    });
}

Why this helps

  • Boot logic is immediately visible
  • Easier to reason about model behavior
  • Less “magic” when scanning the class

#[Initialize] — Running logic on model instantiation

The #[Initialize] attribute marks a method that runs when a model is instantiated.

use Illuminate\Database\Eloquent\Attributes\Initialize;

#[Initialize]
public function initializeDefaults()
{
    $this->status ??= 'draft';
}

Common use cases

  • Setting default attribute values
  • Normalizing initial state
  • Preparing derived properties

#[ObservedBy] — Attaching observers directly to models

Instead of registering observers in a service provider, you can attach them directly to the model.

use Illuminate\Database\Eloquent\Attributes\ObservedBy;

#[ObservedBy(PostObserver::class)]
class Post extends Model
{
}

Why this is nice

  • Observer relationships are visible at the model level
  • No hunting through providers
  • Clear ownership of side effects

Laravel docs: https://laravel.com/docs/12.x/eloquent#observers

#[Scope] — Declaring local query scopes

The #[Scope] attribute marks a method as a local query scope.

use Illuminate\Database\Eloquent\Attributes\Scope;

#[Scope]
public function published($query)
{
    return $query->whereNotNull('published_at');
}

Usage:

Post::published()->get();

Benefits

  • Explicit scope declaration
  • Cleaner than relying solely on method naming

Laravel docs: https://laravel.com/docs/12.x/eloquent#local-scopes

#[ScopedBy] — Applying global scopes cleanly

Use #[ScopedBy] to apply a global scope class to a model.

use Illuminate\Database\Eloquent\Attributes\ScopedBy;

#[ScopedBy(ActiveScope::class)]
class User extends Model
{
}

Ideal for

  • Multi-tenant applications
  • Business rules that should always apply
  • Avoiding duplicated where clauses

Laravel docs: https://laravel.com/docs/12.x/eloquent#global-scopes

#[CollectedBy] — Customizing model collections

This attribute specifies which collection class should be used when retrieving multiple models.

use Illuminate\Database\Eloquent\Attributes\CollectedBy;

#[CollectedBy(CustomPostCollection::class)]
class Post extends Model
{
}

Why it matters

  • Cleaner than overriding newCollection() method.
  • Keeps collection behavior close to the model

Docs: https://laravel.com/docs/12.x/eloquent-collections#custom-collections

#[UseEloquentBuilder] — Assigning a custom query builder

I actually previously wrote about this. Use this when your model benefits from a richer query API.

use Illuminate\Database\Eloquent\Attributes\UseEloquentBuilder;

#[UseEloquentBuilder(PostBuilder::class)]
class Post extends Model
{
}

When this shines

  • Domain-specific queries
  • Reusable query logic
  • Fluent, expressive APIs

This pairs well with advanced querying patterns and avoids bloated models.

#[UseFactory] — Explicit factory mapping

Instead of relying on conventions, you can explicitly define a model’s factory.

use Illuminate\Database\Eloquent\Attributes\UseFactory;

#[UseFactory(PostFactory::class)]
class Post extends Model
{
}

Why use it

  • Clear factory ownership
  • Less convention-based guessing

Docs: https://laravel.com/docs/12.x/eloquent-factories#factory-and-model-discovery-conventions

#[UsePolicy] — Declaring authorization policies

Attach a policy directly to the model.

use Illuminate\Database\Eloquent\Attributes\UsePolicy;

#[UsePolicy(PostPolicy::class)]
class Post extends Model
{
}

Benefits:

  • Authorization rules are discoverable
  • No indirection via AuthServiceProvider

Docs: https://laravel.com/docs/12.x/authorization#manually-registering-policies

#[UseResource] — Assigning API resources

For API-driven applications, you can define a default resource.

use Illuminate\Database\Eloquent\Attributes\UseResource;

#[UseResource(PostResource::class)]
class Post extends Model
{
}

Docs: https://laravel.com/docs/12.x/eloquent-resources#concept-overview

#[UseResourceCollection] — Assigning resource collections

Likewise, you can define a default resource collection.

use Illuminate\Database\Eloquent\Attributes\UseResourceCollection;

#[UseResourceCollection(PostCollection::class)]
class Post extends Model
{
}

Docs: https://laravel.com/docs/12.x/eloquent-resources#resource-collections

When should you use these attributes?

These attributes work best when:

  • You value explicitness over convention
  • The codebase is shared across a team
  • Models have non-trivial behavior
  • Long-term maintainability matters

You may want to avoid overusing them in:

  • Very small projects
  • Simple CRUD-only models
  • Situations where conventions are already clear

As always, clarity beats cleverness.

Final Thoughts

Eloquent model attributes don’t replace understanding Laravel’s core behavior—but they make that behavior more visible.

When used thoughtfully, they can reduce hidden wiring, improve discoverability and make intent clear to future readers.

They’re another tool in the box—not a requirement—but a powerful one when used intentionally.

By the way

I’m currently building SignDeck, a lightweight tool for collecting client documents and e-Signatures without the usual back-and-forth emails. If you work with clients, you might find it useful.

Check out the features here!

Marvin Quezon

Marvin Quezon

Full Stack Web Developer

Marvin Quezon · Copyright © 2026 · Privacy · Sitemap