Laravel Reverb
Laravel Reverb: Real-Time WebSockets Made Simple
Build real-time applications with Laravel Reverb. Learn WebSocket setup, broadcasting events, private channels, presence channels, and Laravel Cloud integration.

Hoceine El Idrissi
Full Stack Developer
Laravel Reverb: Real-Time WebSockets Made Simple
Laravel Reverb is the official first-party WebSocket server for Laravel, providing blazing-fast real-time communication directly within your Laravel ecosystem.
Why Reverb?
- Native Integration - Works seamlessly with Laravel Broadcasting
- High Performance - Handles thousands of concurrent connections
- Zero Configuration - Works out of the box
- Scalable - Horizontal scaling with Redis clustering
Installation
php artisan install:broadcasting
This automatically:
- Installs Reverb
- Configures broadcasting
- Sets up Laravel Echo
Environment Configuration
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=my-app
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret
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}"
Starting the Server
php artisan reverb:start
# With options
php artisan reverb:start --host=0.0.0.0 --port=8080 --debug
Broadcasting Events
Creating Events
// app/Events/MessageSent.php
class MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(
public Message $message,
public User $user
) {}
public function broadcastOn(): array
{
return [
new PrivateChannel('chat.' . $this->message->room_id),
];
}
public function broadcastAs(): string
{
return 'message.sent';
}
public function broadcastWith(): array
{
return [
'id' => $this->message->id,
'content' => $this->message->content,
'user' => [
'id' => $this->user->id,
'name' => $this->user->name,
'avatar' => $this->user->avatar_url,
],
'created_at' => $this->message->created_at->toISOString(),
];
}
}
Dispatching Events
// In controller or service
event(new MessageSent($message, auth()->user()));
// Or use broadcast helper
broadcast(new MessageSent($message, auth()->user()));
// Broadcast to others only (exclude sender)
broadcast(new MessageSent($message, auth()->user()))->toOthers();
Channel Types
Public Channels
Anyone can listen:
public function broadcastOn(): Channel
{
return new Channel('updates');
}
Echo.channel('updates')
.listen('.update.published', (e) => {
console.log(e.data);
});
Private Channels
Requires authentication:
// Event
public function broadcastOn(): PrivateChannel
{
return new PrivateChannel('user.' . $this->userId);
}
// routes/channels.php
Broadcast::channel('user.{id}', function (User $user, int $id) {
return $user->id === $id;
});
Echo.private(`user.${userId}`)
.listen('.notification', (e) => {
showNotification(e);
});
Presence Channels
Track who's online:
// Event
public function broadcastOn(): PresenceChannel
{
return new PresenceChannel('room.' . $this->roomId);
}
// routes/channels.php
Broadcast::channel('room.{roomId}', function (User $user, int $roomId) {
if ($user->canJoinRoom($roomId)) {
return [
'id' => $user->id,
'name' => $user->name,
'avatar' => $user->avatar_url,
];
}
});
Echo.join(`room.${roomId}`)
.here((users) => {
this.onlineUsers = users;
})
.joining((user) => {
this.onlineUsers.push(user);
showToast(`${user.name} joined`);
})
.leaving((user) => {
this.onlineUsers = this.onlineUsers.filter(u => u.id !== user.id);
showToast(`${user.name} left`);
})
.listen('.message.sent', (e) => {
this.messages.push(e);
});
Client-Side Setup
Laravel Echo Configuration
// resources/js/bootstrap.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'],
});
Vue.js Integration
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
const messages = ref([]);
const onlineUsers = ref([]);
onMounted(() => {
Echo.join(`room.${roomId}`)
.here((users) => {
onlineUsers.value = users;
})
.joining((user) => {
onlineUsers.value.push(user);
})
.leaving((user) => {
onlineUsers.value = onlineUsers.value.filter(u => u.id !== user.id);
})
.listen('.message.sent', (e) => {
messages.value.push(e);
});
});
onUnmounted(() => {
Echo.leave(`room.${roomId}`);
});
</script>
Real-Time Notifications
// app/Notifications/OrderShipped.php
class OrderShipped extends Notification implements ShouldBroadcast
{
public function __construct(
public Order $order
) {}
public function via($notifiable): array
{
return ['database', 'broadcast'];
}
public function toBroadcast($notifiable): BroadcastMessage
{
return new BroadcastMessage([
'title' => 'Order Shipped!',
'body' => "Your order #{$this->order->number} has been shipped.",
'action_url' => route('orders.show', $this->order),
]);
}
}
// Listen for notifications
Echo.private(`App.Models.User.${userId}`)
.notification((notification) => {
showNotification(notification);
});
Whisper (Client Events)
Send events directly from client to client:
// Typing indicator
const input = document.querySelector('#message-input');
input.addEventListener('input', () => {
Echo.private(`room.${roomId}`)
.whisper('typing', {
user: currentUser.name
});
});
// Listen for whispers
Echo.private(`room.${roomId}`)
.listenForWhisper('typing', (e) => {
showTypingIndicator(e.user);
});
Laravel Cloud Integration
Deploy WebSockets instantly with Laravel Cloud:
# Enable WebSockets in cloud.yaml
services:
web:
websockets:
enabled: true
Features:
- Managed Reverb clusters
- Auto-scaling
- Zero configuration
- 50% cheaper than alternatives
Production Configuration
Supervisor Setup
[program:reverb]
process_name=%(program_name)s
command=php /var/www/app/artisan reverb:start --host=0.0.0.0 --port=8080
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/app/storage/logs/reverb.log
stopwaitsecs=3600
Nginx Configuration
server {
listen 443 ssl;
server_name ws.example.com;
ssl_certificate /etc/ssl/certs/example.com.pem;
ssl_certificate_key /etc/ssl/private/example.com.key;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}
}
Scaling with Redis
REVERB_SCALING_ENABLED=true
REVERB_SCALING_CHANNEL=reverb
// config/reverb.php
'scaling' => [
'enabled' => env('REVERB_SCALING_ENABLED', false),
'channel' => env('REVERB_SCALING_CHANNEL', 'reverb'),
],
Monitoring with Laravel Pulse
// config/pulse.php
'recorders' => [
\Laravel\Reverb\Pulse\Recorders\ReverbConnections::class => [],
\Laravel\Reverb\Pulse\Recorders\ReverbMessages::class => [],
],
Conclusion
Laravel Reverb makes real-time features accessible to every Laravel developer. With native integration, excellent performance, and Laravel Cloud support, building real-time applications has never been easier.