Laravel 13 now lets you replace the $table, $fillable and $casts properties that crowd most models with native PHP attributes. The change applies to more than a dozen framework features, from model configuration to event listeners and mailables, and it works without breaking existing code.

Why Laravel added native attributes

Laravel has long relied on “magic strings” – arrays of column names or hidden fields that sit in the top of a model class. Those arrays give the IDE no hint about the underlying schema, so refactoring a column name can slip through unnoticed. By moving configuration into real, typed code, Laravel gives developers a way to keep the class body focused on business logic while letting the editor surface autocomplete, type-checking and rename-refactor tools.

The framework reads attributes via PHP’s reflection API and caches the result, so the runtime overhead is effectively zero. Existing property-based models continue to work exactly as they do today, which means you can adopt the new syntax gradually.

What you gain

  • Typed configuration – Attributes accept typed arguments, eliminating magic strings. Rename a column and the IDE points out every place you need to update.
  • Cleaner class bodies – All configuration lives above the class name; the body contains only relationships, scopes and methods.
  • Better IDE experience – Autocomplete and static analysis work on attribute arguments, something arrays of strings can’t provide.
  • No breaking changes – Laravel reads both the old properties and the new attributes, so a mixed codebase runs without issue.

Step-by-step migration guide

  1. Identify the model to migrate
    Open the model file. If the first dozen lines are dominated by $table, $fillable, $hidden or a casts() method, it’s a candidate.

  2. Add the attribute classes
    At the top of the file, import the attribute classes that correspond to the properties you’ll replace (e.g., Table, Fillable, Casts). Laravel ships these attributes out of the box.

  3. Replace property declarations with attributes

    // Before
    protected $table = 'site_deployments';
    protected $fillable = ['site_id', 'server_id', 'status'];
    protected function casts(): array
    {
        return ['is_rollback' => 'boolean'];
    }
    
    // After
    #[Table('site_deployments')]
    #[Fillable(['site_id', 'server_id', 'status'])]
    #[Casts(['is_rollback' => 'boolean'])]
    class Deployment extends Model
    {
        // business logic only
    }
    

    The attribute syntax sits directly above the class declaration. Remove the original property or method after confirming the attribute works.

  4. Run the test suite
    Verify that mass-assignment, serialization and any custom casting still behave as before. Laravel’s attribute handling is cached, so a failing test usually points to a typo in the attribute arguments.

  5. Commit and deploy in small batches
    Push the migrated model to a feature branch, merge it after the CI pipeline passes, and roll it out to a subset of servers. Because the old property syntax is still supported, any stray reference will not cause a runtime error.

  6. Repeat per namespace
    Instead of rewriting the entire codebase at once, move one logical group of models (e.g., all billing-related entities) to attributes, then repeat for the next group. This limits the blast radius of any regression.

Tools and safety nets

  • Rector – An automated refactoring tool that can convert the repetitive property syntax into attributes. Run it on a copy of the codebase, review the diff, and apply the changes that look correct.
  • Automated tests – Laravel’s built-in testing utilities catch discrepancies in mass-assignment and JSON output. Keep them green after each migration step.
  • Feature flags – If you need to roll back quickly, wrap the new attribute usage behind a flag that toggles between the old and new configuration.

When you might skip the migration

If a project is small, stable and rarely touched, the benefit of cleaner models may not outweigh the effort of conversion. The attribute syntax is optional; you can continue using the classic property approach indefinitely. Conversely, for actively developed applications, especially those with large models or frequent schema changes, adopting attributes early reduces future friction.

What to watch next

Laravel 13’s attribute support expands beyond models to event listeners, notifications, mailables and broadcast events. As the community adopts the syntax in those areas, similar refactoring patterns will emerge. Keep an eye on the official upgrade guide for any new attribute classes that land in future minor releases.

Muhtasari: Laravel 13 inakupa njia isiyo na gharama ya kupata modeli nyepesi zaidi na zinazofaa zaidi kwa IDE. Badilisha kila namespace moja baada ya nyingine, tumia Rector na seti yako ya majaribio, na utamalizia na madarasa ambayo yanasomeka kama maelezo ya biashara badala ya mafaili ya kutoa mipangilio.