Skip to main content

Overview

Every time an Eloquent model is instantiated it runs two phases: boot (once per class) and initialize (once per instance). When you define specific methods in a trait, Eloquent automatically discovers and calls them. Adding the trait to a model is all that’s needed. Laravel itself uses this pattern extensively in traits like SoftDeletes, HasUuids, and HasUlids.

boot vs. initialize

bootXxx()initializeXxx()
When calledOnce when the model class first bootsEvery time an instance is created
Method typestaticInstance method
Typical useRegister event listeners, add global scopesSet default attribute values, merge casts

Naming Conventions

bootXxx()

Define a static method prefixed with boot followed by the trait’s class basename. Eloquent calls it once per class lifecycle.
namespace App\Models\Concerns;

trait HasSlug
{
    public static function bootHasSlug(): void
    {
        static::creating(function ($model) {
            if (empty($model->slug)) {
                $model->slug = str($model->name)->slug()->toString();
            }
        });
    }
}
Using the trait in a model:
use App\Models\Concerns\HasSlug;

class Article extends Model
{
    use HasSlug;
    // bootHasSlug() is called automatically
}

initializeXxx()

Define an instance method prefixed with initialize followed by the trait’s class basename. Eloquent calls it every time a new instance is created.
namespace App\Models\Concerns;

trait HasDefaultStatus
{
    public function initializeHasDefaultStatus(): void
    {
        $this->attributes['status'] ??= 'draft';
    }
}
Dynamically merging casts is another common use:
trait HasMetadata
{
    public function initializeHasMetadata(): void
    {
        $this->mergeCasts([
            'metadata' => 'array',
        ]);
    }
}

PHP Attributes

Since Laravel 11, you can use PHP Attributes instead of relying on naming conventions.
AttributePurpose
#[Boot]Mark a static method to run once when the class boots
#[Initialize]Mark an instance method to run on every instantiation
use Illuminate\Database\Eloquent\Attributes\Boot;
use Illuminate\Database\Eloquent\Attributes\Initialize;

trait HasAuditLog
{
    #[Boot]
    public static function registerAuditListeners(): void
    {
        static::created(function ($model) {
            AuditLog::record('created', $model);
        });

        static::updated(function ($model) {
            AuditLog::record('updated', $model);
        });
    }

    #[Initialize]
    public function setAuditDefaults(): void
    {
        $this->attributes['audit_enabled'] ??= true;
    }
}
Using PHP Attributes frees your method names from the trait-name constraint. You can also define multiple #[Boot] or #[Initialize] methods within the same trait.

Practical Examples

Adding a Global Scope Automatically

trait HasTenant
{
    public static function bootHasTenant(): void
    {
        static::addGlobalScope(new TenantScope);
    }
}

Merging Default Casts

trait HasJsonSettings
{
    public function initializeHasJsonSettings(): void
    {
        $this->mergeCasts([
            'settings' => 'array',
        ]);
    }
}

Auto-archiving on Delete

trait Archivable
{
    #[Boot]
    public static function bootArchivable(): void
    {
        static::deleting(function ($model) {
            Archive::store($model->toArray());
        });
    }
}

Examples in the Framework

Laravel’s own traits demonstrate the pattern clearly:
TraitMethodWhat it does
SoftDeletesbootSoftDeletes()Registers the SoftDeletingScope global scope
HasUlidsbootHasUlids()Sets ULID on the creating event
HasUuidsbootHasUuids()Sets UUID on the creating event
Reading these implementations is a great way to understand the pattern in depth.

Caveats

Clearing Booted Models in Tests

Because boot* runs only once per class, tests that alter model behavior may need to reset the boot cache:
protected function tearDown(): void
{
    Model::clearBootedModels();
    parent::tearDown();
}

Execution Order

When a model uses multiple traits, bootXxx() and initializeXxx() are called in PHP’s trait resolution order (declaration order). Be mindful of ordering when traits depend on each other.

Summary

PatternHow to defineWhen to use
Class bootstatic bootXxx() or #[Boot]Event listeners, global scopes
Instance initinitializeXxx() or #[Initialize]Default values, dynamic casts
Implementing bootXxx() and initializeXxx() in a trait lets you inject behavior into any Eloquent model with a single use statement — the go-to pattern for package authors.
Last modified on July 13, 2026