Establishing real-time notifications in contemporary web applications has become a necessity – chat messages, order changes, system alerts, and live dashboards are just a few examples. Laravel Reverb by Laravel allows developers to easily create fast and secure WebSocket servers to enable real-time broadcasting. Using Laravel Reverb enables blazing-fast, scalable, and easy-to-use real-time WebSocket communication in Laravel applications. It integrates seamlessly with the existing suite of event broadcasting tools offered by Laravel and contains a high-performance WebSocket server.

This blog article will explain what Laravel Reverb is and how it functions, and provide an example of using Laravel’s built-in notification and broadcasting system to create a real-time notification.
Steps for Laravel Reverb Real-Time Notifications:
Step 1: Install Laravel
composer create-project laravel/laravel example-appStep 2: Create Auth using Scaffold
composer require laravel/uiGenerate Auth:
php artisan ui bootstrap --auth
npm install
npm run buildStep 3: Create Migrations
php artisan make:migration add_is_admin_column_table
php artisan make:migration create_posts_tableOpen this file: database/migrations/2024_06_18_140624_add_is_admin_column.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->tinyInteger('is_admin')->default(0);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
//
}
};Open this file: database/migrations/2024_06_18_140906_create_posts_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('posts');
}
};php artisan migrateStep 4: Create and Update Models
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = ['title', 'body', 'user_id'];
/**
* Write code on Method
*
* @return response()
*/
public function user()
{
return $this->belongsTo(User::class);
}
}app/Models/User.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'email',
'password',
'is_admin'
];
/**
* The attributes that should be hidden for serialization.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* Get the attributes that should be cast.
*
* @return array
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}Step 5: Setup Reverb & Echo Server
php artisan install:broadcasting
composer require laravel/reverb
php artisan reverb:install
npm install --save-dev laravel-echoNow, you will see some code on the echo.js file, where you can made a changes:
resources/js/echo.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});Then, set the BROADCAST_CONNECTION environment variable to Reverb in your application’s .env file, also we will add Reverb env variables:
.env
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=256980
REVERB_APP_KEY=f4l2tmwqf6eg0f6jz0mw
REVERB_APP_SECRET=zioqeto9xrytlnlg7sj6
REVERB_HOST="localhost"
REVERB_PORT=8080
REVERB_SCHEME=http
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"Now again build your JS:
npm run buildStep 6: Create PostCreate Event
Next, run the following command to create an event class.
php artisan make:event PostCreateapp/Events/PostCreate.php
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
class PostCreate implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $post;
/**
* Create a new event instance.
*/
public function __construct($post)
{
$this->post = $post;
}
/**
* Write code on Method
*
* @return response()
*/
public function broadcastOn()
{
return new Channel('posts');
}
/**
* Write code on Method
*
* @return response()
*/
public function broadcastAs()
{
return 'create';
}
/**
* Get the data to broadcast.
*
* @return array
*/
public function broadcastWith(): array
{
return [
'message' => "[{$this->post->created_at}] New Post Received with title '{$this->post->title}'."
];
}
}Step 7: Create Routes
routes/web.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::post('/posts', [PostController::class, 'store'])->name('posts.store');Step 8: Create Controller
app/Http/Controllers/PostController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Post;
use App\Events\PostCreate;
class PostController extends Controller
{
/**
* Write code on Method
*
* @return response()
*/
public function index(Request $request)
{
$posts = Post::get();
return view('posts', compact('posts'));
}
/**
* Write code on Method
*
* @return response()
*/
public function store(Request $request)
{
$this->validate($request, [
'title' => 'required',
'body' => 'required'
]);
$post = Post::create([
'user_id' => auth()->id(),
'title' => $request->title,
'body' => $request->body
]);
event(new PostCreate($post));
return back()->with('success','Post created successfully.');
}
}Step 9: Create and Update Blade Files
resources/views/layouts/app.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=Nunito" rel="stylesheet">
<!-- Scripts -->
@vite(['resources/sass/app.scss', 'resources/js/app.js'])
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
@yield('script')
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
Laravel Send Realtime Notification using Reverb
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav me-auto">
</ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ms-auto">
<!-- Authentication Links -->
@guest
@if (Route::has('login'))
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
</li>
@endif
@if (Route::has('register'))
<li class="nav-item">
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
</li>
@endif
@else
<li class="nav-item">
<a class="nav-link" href="{{ route('posts.index') }}">{{ __('Posts') }}</a>
</li>
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ Auth::user()->name }}
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('Logout') }}
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
@csrf
</form>
</div>
</li>
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4">
@yield('content')
</main>
</div>
</body>
</html>resources/views/posts.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-12">
<div class="card">
<div class="card-header"><i class="fa fa-list"></i> {{ __('Posts List') }}</div>
<div class="card-body">
@session('success')
<div class="alert alert-success" role="alert">
{{ $value }}
</div>
@endsession
<div id="notification">
</div>
@if(!auth()->user()->is_admin)
<p><strong>Create New Post</strong></p>
<form method="post" action="{{ route('posts.store') }}" enctype="multipart/form-data">
@csrf
<div class="form-group">
<label>Title:</label>
<input type="text" name="title" class="form-control" />
@error('title')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="form-group">
<label>Body:</label>
<textarea class="form-control" name="body"></textarea>
@error('body')
<div class="text-danger">{{ $message }}</div>
@enderror
</div>
<div class="form-group mt-2">
<button type="submit" class="btn btn-success btn-block"><i class="fa fa-save"></i> Submit</button>
</div>
</form>
@endif
<p class="mt-4"><strong>Post List:</strong></p>
<table class="table table-bordered data-table">
<thead>
<tr>
<th width="70px">ID</th>
<th>Title</th>
<th>Body</th>
</tr>
</thead>
<tbody>
@forelse($posts as $post)
<tr>
<td>{{ $post->id }}</td>
<td>{{ $post->title }}</td>
<td>{{ $post->body }}</td>
</tr>
@empty
<tr>
<td colspan="5">There are no posts.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
@endsection
@section('script')
@if(auth()->user()->is_admin)
<script type="module">
window.Echo.channel('posts')
.listen('.create', (data) => {
console.log('Order status updated: ', data);
var d1 = document.getElementById('notification');
d1.insertAdjacentHTML('beforeend', '<div class="alert alert-success alert-dismissible fade show"><span><i class="fa fa-circle-check"></i> '+data.message+'</span></div>');
});
</script>
@endif
@endsection@endsection
Step 10: Create Admin User
php artisan make:seeder CreateAdminUserdatabase/seeders/CreateAdminUser.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\User;
class CreateAdminUser extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
User::create([
'name' => 'Admin',
'email' => 'admin@gmail.com',
'password' => bcrypt('123456'),
'is_admin' => 1
]);
}
}Code:
php artisan db:seed --class=CreateAdminUserRun Laravel App:
php artisan serve
php artisan reverb:startConclusion
Laravel Reverb offers the simplest method of creating real-time notifications in Laravel applications. With first-party support and seamless integration, Laravel Reverb is an ideal choice for developing modern, interactive applications.
If you are already using Laravel Broadcasting and Notifications, you will find that migrating to Reverb is the logical next step.

FAQ
1. What is Laravel Reverb used for?
Laravel Reverb is a tool for designing real-time WebSocket communication systems in Laravel applications, including notifications, live updates, and event broadcasting.
2. Is Laravel Reverb better than Pusher?
If you are looking for a solution without third-party dependencies and with complete control over your installation, Laravel Reverb is the best option. However, if you need a managed service solution that offers rapid scalability and no server management, then Pusher will work well for you.
3. Can I use Laravel Reverb with notifications?
Definitely! You can use Laravel Reverb with the Laravel Notification System to deliver notifications in real-time.



