Muhammad Yasir Amin

Loading websiteโ€ฆ

More from Muhammad Yasir Amin

Build Along With Me

Practical walkthroughs on Laravel, React, APIs and deployment workflows.

Subscribe on YouTube

Laravel 13 Database Notifications: Send, Read and Mark as Read

๐Ÿ› ๏ธ Laravel Tutorials4 min read

Laravel 13 Database Notifications: Send, Read and Mark as Read

Muhammad Yasir Amin

Muhammad Yasir Amin

Senior Full Stack Engineerโ€ขNov 9, 2026
Laravel 13 Database Notifications: Send, Read and Mark as Read

To store notifications in the database in Laravel 13, run php artisan make:notifications-table and migrate, create a notification class whose via() returns ['database'], and send it with $user->notify(new YourNotification()). Read them back with $user->unreadNotifications.

This tutorial builds an "order shipped" notification, lists unread items, marks them as read and covers the mistakes that make notifications disappear.

What do I need first?

  • Laravel 13 (current stable at the time of writing) with a supported PHP version.
  • The default User model, which already uses the Notifiable trait.
  • A migrated database.

How do I create the notifications table?

Code
php artisan make:notifications-table
php artisan migrate

The table stores the notification type (the class name), the notifiable model, a JSON data column and a nullable read_at timestamp. If your users use UUID or ULID primary keys, edit the migration and replace morphs with uuidMorphs or ulidMorphs before migrating.

How do I create a notification class?

Code
php artisan make:notification OrderShipped
JavaScript
<?php

namespace App\Notifications;

use App\Models\Order;
use Illuminate\Notifications\Notification;

class OrderShipped extends Notification
{
    public function __construct(public Order $order)
    {
    }

    public function via(object $notifiable): array
    {
        return ['database'];
    }

    public function toArray(object $notifiable): array
    {
        return [
            'order_id' => $this->order->id,
            'message'  => 'Your order #'.$this->order->id.' has shipped.',
        ];
    }
}

The array returned by toArray() is encoded to JSON and saved in the data column. Keep it small and store ids plus display text, not whole models. If the same class also broadcasts to a websocket channel, define toDatabase() separately so each channel gets its own payload.

How do I send it?

PHP
$user->notify(new OrderShipped($order));

You can also send to many users at once with the Notification facade:

PHP
use Illuminate\Support\Facades\Notification;

Notification::send($users, new OrderShipped($order));

How do I read notifications?

PHP
$user = auth()->user();

$all    = $user->notifications;          // newest first
$unread = $user->unreadNotifications;
$read   = $user->readNotifications;

$count = $user->unreadNotifications()->count();

foreach ($unread as $notification) {
    echo $notification->data['message'];
}

How do I show them in a controller and view?

JavaScript
public function index(Request $request)
{
    return view('notifications.index', [
        'notifications' => $request->user()->notifications()->paginate(15),
    ]);
}
Shell
@foreach ($notifications as $notification)
    <div class="{{ $notification->read_at ? '' : 'fw-bold' }}">
        {{ $notification->data['message'] }}
        <small>{{ $notification->created_at->diffForHumans() }}</small>
    </div>
@endforeach

{{ $notifications->links() }}

Reading through the notifications() relationship scopes the query to the signed-in user, so one user cannot read another user's notifications.

How do I mark notifications as read?

JavaScript
// one notification
$request->user()->notifications()->findOrFail($id)->markAsRead();

// every unread notification
$request->user()->unreadNotifications->markAsRead();

// bulk update without loading models
$request->user()->unreadNotifications()->update(['read_at' => now()]);

Use the last form for large lists because it runs a single SQL update. To remove them entirely, call $user->notifications()->delete().

Should I queue the notification?

Writing one database row is cheap, so queueing is optional. If the notification also sends email or SMS, add implements ShouldQueue and the Queueable trait so slow channels do not block the request. Run a worker with php artisan queue:work.

What are the common mistakes?

  • Forgetting the table. The error "Base table or view not found: notifications" means you did not run the command and migration.
  • Returning models from toArray(). Store plain values only.
  • Using the wrong notifiable. The model must use the Notifiable trait.
  • Queued notification with no worker. Nothing is stored until a worker runs.
  • Exposing all notifications. Always read them through the authenticated user.

How do I verify it works?

JavaScript
use Illuminate\Support\Facades\Notification;

public function test_order_shipped_notification_is_sent(): void
{
    Notification::fake();

    $user  = User::factory()->create();
    $order = Order::factory()->create();

    $user->notify(new OrderShipped($order));

    Notification::assertSentTo($user, OrderShipped::class);
}

For a real check, send one in php artisan tinker and then run $user->unreadNotifications->count().

FAQ

Where are the notifications stored?

In the notifications table, with the payload in the data JSON column.

Can one class use several channels?

Yes. Return ['database', 'mail'] from via() and add a toMail() method.

How do I change the stored type?

Define a databaseType() method on the notification to return your own string.

References

Article Index & Topic Tags
LaravelDatabaseEloquentNotifications

YouTube Channel

Build Along With Me

Practical walkthroughs on Laravel, React, APIs and deployment workflows.

Muhammad Yasir Amin
Available for Contracts
Author & Solutions Architect

Senior Full Stack Engineer

Independent Senior Full Stack Engineer working on Laravel, React and Next.js applications, APIs and delivery workflows.

Laravel & PHP ApplicationsReact & Next.js InterfacesREST APIs & IntegrationsDatabase Queries & DebuggingDocker Development WorkflowsClear Scope & Handover
Discuss Your Next Step

What Does Your Application Need Next?

Share your current system, the problem you want to solve and what a useful result looks like. We can identify the right starting point and agree on a practical scope.

Technical Audit

Find the Next Useful Fix

Application Development

Scoped, Reviewable Milestones

Ongoing Support

Agreed Capacity and Priorities

Share your goals, current stack and requirements before the call.