Adding Real Time Chat to Laravel Using Reverb & Vue

Last updated on by

Laravel, the web artisan's favorite PHP framework, has just got a whole new powerful tool in its arsenal: Reverb. Among the official packages of Laravel, this WebSocket server application would seamlessly let you integrate real-time features in your Laravel-based applications, thereby taking interaction to a whole new level.

What is Laravel Reverb?

Reverb acts as a mediator between your Laravel-based application and its users. It establishes two-way, real-time communication based on WebSockets technology that allows web pages to receive updates on the server without a complete page refresh. This means that your users experience your application more dynamically and responsively.

Key Features of Laravel Reverb

Blazing Speed: Provides outstanding performance for real-time information with no lags.

Scalability: Grow with your applications to handle increased user traffic.

Seamless Integration: It works with broadcasting features added to Laravel and Laravel Echo to make development simple.

Push Updates: Push updates, messages, or events to clients to share your information instantly.

Built-in Security: Data encryption and authentication assurance for security communication

Adding Laravel Reverb to Your Chat Project

With Laravel Reverb, you can build dynamic chat applications. The messages are posted instantly, making users involved comprehensively. Here's a breakdown of the steps involved:

Step 1: Setting Up Your Laravel Project:

  • Ensure you have a Laravel application set up (version 11 or above is recommended).

  • If you're starting fresh, use composer create-project laravel/laravel your-chat-app-name.

Step 2: Install and Configure Reverb:

Install Laravel Reverb by running the following command:

php artisan install:broadcasting

Once you’ve installed Reverb, you can now modify its configuration from the config/reverb.php file. To establish a connection to Reverb, a set of Reverb “application” credentials must be exchanged between the client and server. These credentials are configured on the server and are used to verify the request from the client. You can define these credentials using the following environment variables:


It also automatically creates echo.js in the resources/js directory.

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'],

Follow the Laravel documentation for configuration steps specific to your application server

Step 3: Running a Server

You can launch the Reverb server by using the reverb:start Artisan command:

php artisan reverb:start

By default, the Reverb server will be started at, which makes it accessible from all network interfaces.

If you want to set a specific host or port, you can use the –host and –port options when starting the server.

php artisan reverb:start --host= --port=9000

You can also define REVERB_SERVER_HOST and REVERB_SERVER_PORT environment variables in your application’s .env configuration file.

Step 4: Setup Database

Open your .env file and adjust the settings to set up your database. Here’s an example using SQLite for simplicity:


You can create an SQLite database by simply running:

touch /path/to/database.sqlite

For this demo, we’ll create five predefined rooms. Let’s start by generating a model ChatMessage with migration for a chat_messages table.

php artisan make:model ChatMessage --migration

To make it simpler, only create name attributes for this model and migrate it.

Schema::create('chat_messages', function (Blueprint $table) {
php artisan migrate

Now, let's add the necessary relationships in the ChatMessage model. Open the ChatMessage.php file in the app/Models directory and update it as follows:

namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class ChatMessage extends Model
use HasFactory;
protected $fillable = [
public function sender()
return $this->belongsTo(User::class, 'sender_id');
public function receiver()
return $this->belongsTo(User::class, 'receiver_id');

Step 5: Create Event

To handle the broadcasting of messages, we'll create an event called MessageSent. This event will implement Laravel's ShouldBroadcastNow interface, which allows for immediate broadcasting over WebSockets without queuing. Follow these steps to create and set up the event:

  1. Create a new PHP file in the App\Events directory and name it MessageSent.php.

  2. Open the newly created file and add the following code:

namespace App\Events;
use App\Models\ChatMessage;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class MessageSent implements ShouldBroadcastNow
use Dispatchable;
use InteractsWithSockets;
use SerializesModels;
* Create a new event instance.
public function __construct(public ChatMessage $message)
* Get the channels the event should broadcast on.
* @return array<int, \Illuminate\Broadcasting\Channel>
public function broadcastOn(): array
return [
new PrivateChannel("chat.{$this->message->receiver_id}"),

Step 6: Create a Private Channel Route

The channels.php file in Laravel applications plays a crucial role in defining broadcast channels used for real-time communication features.

use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('chat.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;

This code defines a private channel named chat.{id} using Laravel's Broadcast facade. Private channels restrict access based on user authentication and authorization logic.

Step 7: Defining Routes

1. Chat Room Route:

Route::get('/chat/{friend}', function (User $friend) {
return view('chat', [
'friend' => $friend

This route is responsible for rendering the chat interface. It accepts a dynamic parameter {friend} representing the user's chat partner.

3. Get Chat Messages Route:

Route::get('/messages/{friend}', function (User $friend) {
return ChatMessage::query()
->where(function ($query) use ($friend) {
$query->where('sender_id', auth()->id())
->where('receiver_id', $friend->id);
->orWhere(function ($query) use ($friend) {
$query->where('sender_id', $friend->id)
->where('receiver_id', auth()->id());
->with(['sender', 'receiver'])
->orderBy('id', 'asc')

This route retrieves chat messages exchanged between the authenticated user and the specified friend ({friend}). The query ensures it retrieves messages where either the user is the sender or receiver, including both directions of the conversation.

4. Send Chat Message Route:

Route::post('/messages/{friend}', function (User $friend) {
$message = ChatMessage::create([
'sender_id' => auth()->id(),
'receiver_id' => $friend->id,
'text' => request()->input('message')
broadcast(new MessageSent($message));
return $message;

After creating the message, it leverages Laravel's broadcasting functionality using broadcast(new MessageSent($message)). This line broadcasts the newly created message to all connected users through Reverb, enabling real-time chat functionality.

Step 8: Creating the Blade View

To render the chat interface, you'll need to create a Blade view file. Create a new file named chat.blade.php in the resources/views directory and add the following code:

<x-slot name="header">
<h2 class="text-xl font-semibold leading-tight text-gray-800">
{{ $friend->name }}
<div class="py-12">
<div class="mx-auto max-w-7xl sm:px-6 lg:px-8">
<div class="overflow-hidden bg-white shadow-sm sm:rounded-lg">
<div class="p-6 bg-white border-b border-gray-200">
:friend="{{ $friend }}"
:current-user="{{ auth()->user() }}"

The key element here is <chat-component :friend="{{ $friend }}" :current-user="{{ auth()->user() }}" />. This line renders a Vue.js component named chat-component.

Step 8: Create a Chat Component

<div class="flex flex-col justify-end h-80">
<div ref="messagesContainer" class="p-4 overflow-y-auto max-h-fit">
v-for="message in messages"
class="flex items-center mb-2"
v-if="message.sender_id ==="
class="p-2 ml-auto text-white bg-blue-500 rounded-lg"
{{ message.text }}
<div v-else class="p-2 mr-auto bg-gray-200 rounded-lg">
{{ message.text }}
<div class="flex items-center">
placeholder="Type a message..."
class="flex-1 px-2 py-1 border rounded-lg"
class="px-4 py-1 ml-2 text-white bg-blue-500 rounded-lg"
<small v-if="isFriendTyping" class="text-gray-700">
{{ }} is typing...
<script setup>
import axios from "axios";
import { nextTick, onMounted, ref, watch } from "vue";
const props = defineProps({
friend: {
type: Object,
required: true,
currentUser: {
type: Object,
required: true,
const messages = ref([]);
const newMessage = ref("");
const messagesContainer = ref(null);
const isFriendTyping = ref(false);
const isFriendTypingTimer = ref(null);
() => {
nextTick(() => {
top: messagesContainer.value.scrollHeight,
behavior: "smooth",
{ deep: true }
const sendMessage = () => {
if (newMessage.value.trim() !== "") {
.post(`/messages/${}`, {
message: newMessage.value,
.then((response) => {
newMessage.value = "";
const sendTypingEvent = () => {
Echo.private(`chat.${}`).whisper("typing", {
onMounted(() => {
axios.get(`/messages/${}`).then((response) => {
messages.value =;
.listen("MessageSent", (response) => {
.listenForWhisper("typing", (response) => {
isFriendTyping.value = response.userID ===;
if (isFriendTypingTimer.value) {
isFriendTypingTimer.value = setTimeout(() => {
isFriendTyping.value = false;
}, 1000);

This Vue.js component manages the chat interface's dynamic behaviour. It displays a scrollable message list, styled differently based on the sender (current user or friend). It provides an input field for composing new messages and a button to send them. It leverages axios for making HTTP requests to fetch initial messages and send new ones.

Real-time functionality is achieved using Laravel Echo:

  1. It listens for broadcasted MessageSent events to update the message list whenever a new message arrives.

  2. It utilizes whispers on private channels to notify the chat partner about the user's typing activity and receive similar notifications from the friend.

Step 9: Run Project

To run the Laravel project, we need to execute the following command:

php artisan serve

For starting front:

npm run dev

Run reverb:

php artisan reverb:start

Source Code

You can find the source code for this Laravel Reverb chat implementation in the following GitHub repository:

By utilizing Laravel Reverb, developers can ensure their applications remain responsive and dynamic, providing real-time updates and interactions that modern users expect. Happy coding!

Harish Kumar photo

Hey, I'm Harish, a full-stack web developer. I teach web development tutorials with practical screencasts on Qirolab Youtube Channel.


Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.

Laravel Forge logo

Laravel Forge

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Forge
Tinkerwell logo


The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

No Compromises logo

No Compromises

Joel and Aaron, the two seasoned devs from the No Compromises podcast, are now available to hire for your Laravel project. ⬧ Flat rate of $7500/mo. ⬧ No lengthy sales process. ⬧ No contracts. ⬧ 100% money back guarantee.

No Compromises
Kirschbaum logo


Providing innovation and stability to ensure your web application succeeds.

Shift logo


Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

Bacancy logo


Supercharge your project with a seasoned Laravel developer with 4-6 years of experience for just $2500/month. Get 160 hours of dedicated expertise & a risk-free 15-day trial. Schedule a call now!

Lucky Media logo

Lucky Media

Get Lucky Now - the ideal choice for Laravel Development, with over a decade of experience!

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel E-Commerce

E-Commerce for Laravel. An open-source package that brings the power of modern headless e-commerce functionality to Laravel.

Lunar: Laravel E-Commerce
LaraJobs logo


The official Laravel job board

SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS Starter Kit

SaaSykit is a Laravel SaaS Starter Kit that comes with all features required to run a modern SaaS. Payments, Beautiful Checkout, Admin Panel, User dashboard, Auth, Ready Components, Stats, Blog, Docs and more.

SaaSykit: Laravel SaaS Starter Kit
Rector logo


Your partner for seamless Laravel upgrades, cutting costs, and accelerating innovation for successful companies

MongoDB logo


Enhance your PHP applications with the powerful integration of MongoDB and Laravel, empowering developers to build applications with ease and efficiency. Support transactional, search, analytics and mobile use cases while using the familiar Eloquent APIs. Discover how MongoDB's flexible, modern database can transform your Laravel applications.


The latest

View all →
A Resize Plugin for Alpine.js image

A Resize Plugin for Alpine.js

Read article
How to Migrate MySQL from DBngin to Laravel Herd image

How to Migrate MySQL from DBngin to Laravel Herd

Read article
Learn to master Query Scopes in Laravel image

Learn to master Query Scopes in Laravel

Read article
How to Redirect Uppercase URLs to Lowercase with Laravel Middleware image

How to Redirect Uppercase URLs to Lowercase with Laravel Middleware

Read article
PHP 8.4 Alpha 1 is now out! image

PHP 8.4 Alpha 1 is now out!

Read article
Generics Added to Eloquent Builder in Laravel 11.15 image

Generics Added to Eloquent Builder in Laravel 11.15

Read article