Laravel 13 Attributes: the most divisive Laravel feature


When Laravel 13 introduced PHP Attributes across Eloquent models, the reaction from the Laravel community was divided. To me this was not a surprise at all! As I started in Symfony use of attributes (and its hacky predecessor docblock annotations) was very logical back then, but once you work a lot with them, you do know of the pitfalls of overuse of attributes. 

To some developers this feels like a cleaner syntax:

#[Fillable(['name', 'email'])]
#[Table('users')]
class User extends Model
{
    //
}

Others looked at the same code and asked a simple question:

“Why replace perfectly fine properties with attributes?”

That tension is interesting because it reveals something deeper about Laravel itself. Laravel has always balanced two competing ideas:

  • expressive developer experience
  • pragmatic simplicity

Laravel 13’s new attribute-based model configuration pushes hard toward expressiveness and modern PHP conventions. But many developers are unconvinced that it actually improves maintainability.

What Changed in Laravel 13?

Historically, Eloquent model configuration lived in protected properties:

class User extends Model
{
    protected $table = 'users';

    protected $fillable = [
        'name',
        'email',
    ];

    protected $timestamps = false;
}

Laravel 13 now allows these to be declared using PHP Attributes instead:

use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\WithoutTimestamps;

#[Table('users')]
#[Fillable(['name', 'email'])]
#[WithoutTimestamps]
class User extends Model
{
    //
}

Laravel also introduced attributes for scopes:

#[Scope]
protected function active(Builder $query): void
{
    $query->where('active', true);
}

The official documentation positions this as a cleaner and more modern API.

Why Some Developers Like It

There are legitimate advantages.

1. Better Alignment With Modern PHP

PHP Attributes are now part of the language ecosystem.

Many modern PHP Frameworks and libraries already use attributes heavily.

Laravel adopting them signals that the framework is evolving with modern PHP rather than staying tied to older patterns.

For developers coming from other ecosystems, this feels natural.

2. Configuration Becomes More Declarative

Attributes separate metadata from implementation details.

Compare:

protected $fillable = ['name'];

vs

#[Fillable(['name'])]

The second version reads more like explicit model metadata than mutable runtime state. Since nothing in the application can modify this attribute it is implied as static configuration. With properties in a class anything can modify this property on the fly in real time.

That distinction matters philosophically, even if functionally they achieve similar outcomes.

3. Reduced Property Clutter

Large Eloquent models often become walls of configuration:

protected $fillable = [];
protected $casts = [];
protected $hidden = [];
protected $appends = [];
protected $with = [];

Attributes can visually compress that setup into something easier to scan.

Especially in models with lots of business logic, removing configuration noise can improve readability. Properties are also not part of a interface, so if Laravel decides to rename a property, the original property will not throw an error. If Laravel would rename an Attribute class, the code would crash instantly.

4. Attributes Work Well for Discovery

IDE tooling increasingly understands attributes well.

Attributes are also easier to inspect programmatically through reflection than parsing class properties or docblocks manually. For example if you want to figure out relations etc. of a eloquent model any tool had no other option in calling all methods on the model and see if a relation object is returned.

That opens doors for future tooling, static analysis, code generation, and AI-assisted frameworks.

Why Many Developers Are Skeptical

This is where the debate becomes more interesting.

Because the criticism is not just “people dislike change.”

A lot of developers genuinely believe the attribute approach is solving a problem that barely existed.

1. Properties Were Already Simple

One of the most common reactions was:

“What benefit does this actually provide?”

That sentiment appeared repeatedly in community discussions around Laravel 13.

The old syntax was already extremely readable:

protected $fillable = ['name'];

Replacing it with:

#[Fillable(['name'])]

does not obviously reduce complexity.

In some cases, it arguably increases it.

2. It Creates Multiple Ways To Do The Same Thing

Laravel has historically struggled with “there are five ways to do this.”

Attributes add yet another configuration style.

Now teams must decide:

  • properties?
  • attributes?
  • traits?
  • fluent APIs?
  • conventions?

Consistency inside a team matters more than syntax aesthetics.

And introducing parallel patterns increases cognitive overhead.

3. Reflection-Based Systems Feel More “Magic”

Laravel already gets criticized for being too magical.

Attributes rely heavily on PHP reflection internally.

Some developers are uncomfortable with moving even more framework behavior into metadata discovery systems rather than explicit code.

As I found on Reddit:

“Java all over again with unreadable annotations.”

That may be exaggerated, but the concern is real.

4. Runtime Overhead Concerns

A few developers raised performance concerns because attributes require reflection.

Technically, reflection is slower than direct property access.

Practically, though, the performance difference is probably irrelevant in real-world Laravel applications because metadata gets cached aggressively. This is very true when opcache is enabled.

Still, even if performance is negligible, some developers question the tradeoff:

if readability is not significantly improved, why add additional abstraction layers?

That’s a fair engineering question.

5. Laravel’s Strength Was Pragmatism

This may be the biggest underlying concern.

Laravel became popular because it often chose practical solutions over academically “pure” architecture. Eloquent itself is intentionally straightforward.

Properties felt simple and attributes feel more framework-heavy.

Some developers worry Laravel is drifting toward “enterprise framework” territory where metadata annotations gradually dominate the codebase.

That fear may be overstated, but it explains the emotional reaction many people had.

The Important Detail Most Discussions Miss

The new attribute system is largely an alternative. Laravel did not remove property-based configuration.

This matters as you can still write:

protected $fillable = ['name'];

and Laravel 13 works perfectly.

That means the debate is less about forced migration and more about preferred coding style.

In practice, most teams will probably settle into one of three camps:

Team StyleLikely Outcome
Conservative Laravel teamsKeep using properties
Modern PHP-oriented teamsAdopt attributes heavily
Mixed teamsUse attributes selectively

And honestly, selective usage may become the healthiest middle ground.

Where Attributes Actually Make Sense

Not every Eloquent feature benefits equally from attributes.

Some uses genuinely feel elegant.

For example, scopes:

#[Scope]
protected function active(Builder $query): void
{
    $query->where('active', true);
}

This is arguably cleaner than relying on naming conventions like scopeActive(). The same could be applied to relations and appending fields.

Attributes also work well for metadata-style declarations:

  • table names
  • timestamp configuration
  • fillable rules
  • observers
  • event registration

These are truly declarative concerns.

Where Properties Still Feel Better

Mutable configuration still feels more natural as properties.

For example:

protected $casts = [
    'settings' => 'array',
];

This reads naturally because it behaves like application state configuration.

Turning everything into attributes risks making ordinary model configuration feel overly ceremonial.

The Real Question Isn’t “Better or Worse”

The real question is:

Does this improve code comprehension for your team?

That answer depends heavily on context.

A senior PHP team already comfortable with attributes across the ecosystem may find Laravel 13 cleaner and more consistent.

A Laravel-first team may see little practical benefit.

Is there a behaviour difference?

The simple answer: yes, but is very subtle. Only if you extend model classes you would notice a difference.
class NewModel extends BaseModel {};
Now if BaseModel uses properties for filled the new class NewModel would have the same filled properties. Now if BaseModel would have used attributes, the filled properties are actually not copied! However I do hope that Laravel will not try to fix this as this would be way to complex to think about what the behaviour would be desired.

So the only other problem I could come up is when you create traits specifically for eloquent to add behaviour to the metadata as now you are dealing with properties and attributes at the same time. I also have no idea which one takes preference if both are defined, but I would not be surprised if some Spatie packages for Eloquent do not work with attributes in Laravel 13 because of the hard assumption that it is always stored in the 'filled' property.

Final Verdict

Laravel 13’s Eloquent Attributes are neither revolutionary nor disastrous.

They are mostly:

  • a modernization effort
  • a consistency improvement
  • a stylistic evolution/syntactic sugar

The criticism is understandable because the old property-based approach was already understandable for most developers, even though there are more robust solutions from a design perspective.

Attributes mostly change how Laravel expresses metadata.

For some developers, that feels cleaner.

For others, it feels unnecessary.

My expectation is that the Laravel ecosystem will eventually land on a hybrid approach:

  • attributes for declarative metadata
  • properties for mutable configuration
  • conventional methods for behavior

And honestly, that balance probably makes the most sense.

Comments