Laravel Observers Explained: From Clean CRUD Hooks to Production-Grade Event Architecture

By TechGeeta
Laravel Observers Explained: From Clean CRUD Hooks to Production-Grade Event Architecture
3 min read

What Is an Observer in Laravel?

In Laravel, an Observer is a class that listens to Eloquent model lifecycle events and encapsulates side effects away from controllers and models.

Instead of this:

public function store(Request $request)
{
   $user = User::create($request->all());
   Mail::to($user->email)->send(new WelcomeMail($user));
}

You move the side effect into an observer tied to the model.


Eloquent Model Events (The Trigger Points)

Laravel fires these events automatically:

  • retrieved

  • creating / created

  • updating / updated

  • saving / saved

  • deleting / deleted

  • restoring / restored

  • forceDeleted

Rule of thumb:

  • Use creating / updating to mutate attributes.

  • Use created / updated for side effects (notifications, logs, jobs).


Basic Implementation

1. Create Observer

php artisan make:observer UserObserver --model=User

This generates:

class UserObserver
{
    public function created(User $user)
    {
        //
    }
}

2. Register the Observer

In AppServiceProvider:

use App\Models\User;
use App\Observers\UserObserver;

public function boot()
{
    User::observe(UserObserver::class);
}

3. Real-World Example: Auto-Generate Slug

public function creating(Post $post)
{
    $post->slug = Str::slug($post->title);
}

Why creating?
Because it runs before insert, allowing attribute mutation.


Practical Use Cases (That Actually Matter)

1. Audit Logging (Production-Grade SaaS)

public function updated(Order $order)
{
    ActivityLog::create([
        'model' => Order::class,
        'model_id' => $order->id,
        'changes' => json_encode($order->getChanges()),
    ]);
}

Use case:

  • Financial platforms

  • Compliance-heavy SaaS

  • Enterprise dashboards


2. Dispatch Jobs Instead of Doing Heavy Work

Never send emails directly in observers.

Bad:

Mail::to($user)->send(new WelcomeMail($user));

Correct:

public function created(User $user)
{
    SendWelcomeEmail::dispatch($user);
}

This keeps request lifecycle fast and scalable.


3. Enforcing Business Rules

Prevent deletion if dependent data exists:

public function deleting(Project $project)
{
    if ($project->tasks()->exists()) {
        throw new \Exception("Cannot delete project with tasks.");
    }
}

Now the rule is centralized, not scattered across controllers.


Advanced Patterns

1. Observer + Domain Events (Clean Architecture)

Instead of putting logic directly in the observer:

public function created(User $user)
{
    event(new UserRegistered($user));
}

This keeps observers thin and moves business logic into listeners.


2. Prevent Infinite Loops

If you update a model inside updated, you can trigger recursion.

Bad:

public function updated(User $user)
{
    $user->update(['synced' => true]);
}

Fix:

$user->updateQuietly(['synced' => true]);

Or:

User::withoutEvents(function () use ($user) {
    $user->update(['synced' => true]);
});

3. Handling Soft Deletes

If using SoftDeletes:

  • deleting runs

  • deleted runs

  • forceDeleted runs only on permanent delete

Design logic accordingly.


4. Queue Observers Globally (High-Scale Apps)

Instead of dispatching jobs manually:

class UserObserver implements ShouldQueue

Now observer logic is queued automatically.

This is powerful in:

  • High-traffic SaaS

  • Marketplace platforms

  • Payment systems


5. Observers in Multi-Tenant Apps

Inject tenant context before persistence:

public function creating(Model $model)
{
    $model->tenant_id = tenant()->id;
}

This guarantees tenant isolation at persistence level.


Performance Considerations

Observers run automatically on every model lifecycle event.

Be careful when:

  • Bulk importing data

  • Running seeders

  • Running migrations

  • Executing batch updates

Disable when needed:

Model::withoutEvents(function () {
    User::insert($bulkData);
});

Observers vs Model Events vs Global Scopes

FeatureUse Case
ObserverSide effects, automation
Model Event ClosureQuick inline logic
Global ScopeQuery filtering
MiddlewareHTTP-level rules

Do not use observers for:

  • Authorization

  • Validation

  • HTTP-level decisions


Anti-Patterns (Avoid These)

  1. Business logic explosion inside observers

  2. Sending emails synchronously

  3. Hidden side effects developers cannot trace

  4. Mutating unrelated models silently

Observers should be:

  • Deterministic

  • Lightweight

  • Transparent


Real SaaS Example Architecture

Imagine a subscription platform:

When Subscription is created:

Observer:

public function created(Subscription $subscription)
{
    SyncWithStripe::dispatch($subscription);
    GenerateInvoice::dispatch($subscription);
    NotifyAdmin::dispatch($subscription);
}

Now:

  • Controllers stay clean

  • Business rules centralized

  • Side effects scalable


Testing Observers Properly

Use:

Event::fake();
Queue::fake();

Or test observer behavior directly:

$user = User::factory()->create();
$this->assertDatabaseHas('activity_logs', [
    'model_id' => $user->id,
]);

When NOT to Use Observers

Do not use them when:

  • Logic depends on HTTP request context

  • You need explicit control over execution order

  • The logic is domain-specific and not model-lifecycle specific

In complex systems, domain events may be cleaner.


Strategic Guidance for Founders & CTOs

Observers are valuable when:

  • You want clean controllers

  • You want automatic system behaviors

  • You need centralized persistence rules

But in large-scale SaaS:

  • Combine Observers with Domain Events

  • Avoid heavy synchronous processing

  • Document side effects clearly


Final Takeaway

Observers are not just “nice Laravel features.”
They are persistence-layer automation tools.

Used properly:

  • They reduce duplication

  • They centralize rules

  • They enforce data integrity

Used poorly:

  • They create hidden chaos

Architect them deliberately.

Stay Updated with Our Latest News

Subscribe to our newsletter and be the first to know about our latest projects, blog posts, and industry insights.