Laravel 13 Attribute Guide: Transitioning from Properties to PHP Attributes
Overview
$fillable or $hidden—with metadata directly above the class or method definition. This change aims to clean up class bodies and utilize native PHP 8 language features for better static analysis and cleaner syntax.
Prerequisites
To use these features, you should have a solid grasp of #[Attribute]). You should also be familiar with
Key Libraries & Tools
- Laravel: The latest version of the PHP framework.
- Eloquent: The database mapper now supporting attribute-based model configuration.
- Livewire: Often paired with these attributes in modern starter kits.

Code Walkthrough
Refactoring Eloquent Models
Previously, you defined model behavior using class properties. In the new version, you apply them as attributes:
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
#[Fillable(['name', 'email'])]
#[Hidden(['password'])]
class User extends Model {}
Laravel reads these attributes at runtime, effectively populating the internal protected properties for you.
Enhancing Queued Jobs
For background tasks, you can now set retry limits and timeouts directly on the class:
use Illuminate\Queue\Attributes\Tries;
use Illuminate\Queue\Attributes\Timeout;
#[Tries(5)]
#[Timeout(60)]
class ProcessPodcast implements ShouldQueue {}
Syntax Notes
Attributes utilize the #[ ] syntax. Unlike properties, attributes can take constructor arguments, allowing for cleaner configuration of complex settings like ExponentialBackoff within a single line. This moves configuration logic out of the class body and into the header.
Practical Examples
You can now define
#[Signature('app:send-emails {user}')]
#[Description('Send a notification email to a specific user')]
class SendEmails extends Command {}
Tips & Gotchas
While $middleware arrays. Additionally, always ensure you import the correct namespace for each attribute to avoid "Attribute not found" errors.

Fancy watching it?
Watch the full video and context