Laravel Reverb in 2026: A PHP WebSocket Server Without Node.js or Third-Party Services
Introduction: The Realtime Problem in PHP Applications
For a long time, PHP was considered a "request-response" language: an HTTP request comes in, a response goes out. Implementing anything in real time meant either pulling Node.js into your stack, paying for Pusher or Ably, or wrestling with a self-hosted Soketi setup. Each of these approaches added complexity: a different runtime, a new service, extra costs, or unreliable self-maintenance.
The history of solutions looked roughly like this:
- Pusher — convenient, but paid, and your data goes to a third-party server.
- Socket.io + Node.js — powerful, but now your project has two runtimes.
- Soketi — a self-hosted, Pusher-compatible server built on Node.js. Better, but still Node.
- Ably — a cloud option with a more generous free tier, but the same dependency on a third party.
In March 2024, the Laravel team introduced Laravel Reverb — the first official WebSocket server written in pure PHP and built directly into the framework's ecosystem. By 2026, it's a mature, production-ready solution. Let's explore how it works and how to use it.
What Is Laravel Reverb and How It Came to Be
Laravel Reverb is a first-class WebSocket server for Laravel, built on top of the ReactPHP library. It is fully compatible with the Pusher Channels protocol, which means frontend code that worked with Pusher or Soketi can switch to Reverb without any changes — you simply update the credentials in your config.
Reverb emerged as a response to one of the most popular community requests: give Laravel developers the ability to build realtime applications without leaving the PHP ecosystem. Joe Dixon and the Laravel team spent several months building an asynchronous event loop on top of ReactPHP, enabling PHP to maintain thousands of open WebSocket connections within a single long-running process.
"Reverb is built so that Laravel developers can build realtime applications just as easily as they build ordinary HTTP endpoints." — the Laravel team
Architecture: How Reverb Works Under the Hood
Understanding Reverb's architecture is important for configuring it correctly and avoiding surprises in production.
Event Loop and ReactPHP
Reverb runs as a long-lived PHP process (it does not die after each request). Internally, it uses an event loop based on ReactPHP, which accepts incoming WebSocket connections and handles messages asynchronously. This is fundamentally different from the standard PHP-FPM model.
Integration with Broadcasting and Events
Laravel Broadcasting is an abstraction over the event transport layer. When you call broadcast(new OrderShipped($order)), Laravel Broadcasting decides where to send the event: to Pusher, Redis, Reverb, or somewhere else. Reverb registers itself as the reverb broadcasting driver.
The chain works like this:
- Your PHP code fires an event via
broadcast(). - Laravel Broadcasting sends it to the Reverb server via HTTP/WebSocket (either through a queue or directly).
- Reverb delivers the message to all subscribed clients on the appropriate channels.
- The frontend receives the event via
laravel-echoand the Pusher JS SDK.
Installation and Basic Reverb Configuration
Let's walk through the installation step by step. This assumes you already have a Laravel 11+ project.
Installing the Package
composer require laravel/reverb
php artisan reverb:install
The reverb:install command publishes the config/reverb.php config file, adds the necessary variables to your .env, and configures Broadcasting to use the reverb driver.
Configuring .env
BROADCAST_DRIVER=reverb
REVERB_APP_ID=my-app-id
REVERB_APP_KEY=my-app-key
REVERB_APP_SECRET=my-app-secret
REVERB_HOST=0.0.0.0
REVERB_PORT=8080
REVERB_SCHEME=http
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="localhost"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"
Starting the Server
php artisan reverb:start
# or with a specific host and port
php artisan reverb:start --host=0.0.0.0 --port=8080
Frontend Setup
Install the dependencies:
npm install --save-dev laravel-echo pusher-js
Configure Echo in 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,
wssPort: import.meta.env.VITE_REVERB_PORT,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});
Scaling Reverb with Redis
A single Reverb instance is great for getting started, but what do you do when load increases and you need multiple servers? That's where Redis comes in.
Reverb supports Redis as a pub/sub backend. When an event is published on one Reverb instance, Redis distributes it to all other instances, which then deliver the message to their connected clients. This is the classic horizontal scaling pattern.
Configuring the Redis Backend
# .env
REVERB_SCALING_ENABLED=true
REVERB_SCALING_DRIVER=redis
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
In config/reverb.php, make sure the scaling section looks like this:
'scaling' => [
'enabled' => env('REVERB_SCALING_ENABLED', false),
'channel' => 'reverb',
'server' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REVERB_SCALING_REDIS_DATABASE', '0'),
],
],
You can now run multiple instances of php artisan reverb:start behind a load balancer, and Redis will synchronize state between them.
Deploying Reverb with Docker and Kubernetes
Docker Configuration
An example Dockerfile for a Laravel application with Reverb:
FROM php:8.3-cli-alpine
RUN apk add --no-cache \
git curl unzip libzip-dev \
&& docker-php-ext-install zip pcntl sockets
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /app
COPY . .
RUN composer install --no-dev --optimize-autoloader
EXPOSE 8080
CMD ["php", "artisan", "reverb:start", "--host=0.0.0.0", "--port=8080"]
An example docker-compose.yml:
version: '3.9'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- APP_ENV=production
- REVERB_APP_ID=my-app-id
- REVERB_APP_KEY=my-app-key
- REVERB_APP_SECRET=my-app-secret
- REVERB_SCALING_ENABLED=true
- REDIS_HOST=redis
depends_on:
- redis
redis:
image: redis:7-alpine
ports:
- "6379:6379"
Kubernetes: Deployment and Service
In Kubernetes, the Reverb server is deployed as a separate Deployment with multiple replicas. WebSocket traffic is routed through a LoadBalancer Service or an Ingress controller with WebSocket support.
apiVersion: apps/v1
kind: Deployment
metadata:
name: reverb
spec:
replicas: 3
selector:
matchLabels:
app: reverb
template:
metadata:
labels:
app: reverb
spec:
containers:
- name: reverb
image: your-registry/laravel-app:latest
command: ["php", "artisan", "reverb:start", "--host=0.0.0.0", "--port=8080"]
ports:
- containerPort: 8080
env:
- name: REVERB_SCALING_ENABLED
value: "true"
- name: REDIS_HOST
value: redis-service
---
apiVersion: v1
kind: Service
metadata:
name: reverb-service
spec:
selector:
app: reverb
ports:
- port: 8080
targetPort: 8080
type: LoadBalancer
Important: make sure your Ingress controller (e.g., nginx-ingress) is configured to support connection upgrades to WebSocket via the Upgrade and Connection headers.
Practical Example: A Real-Time Chat
Let's build a simple public chat using Laravel Broadcasting and Vue 3.
Server-Side Event
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
class MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets;
public function __construct(
public string $message,
public string $username
) {}
public function broadcastOn(): Channel
{
return new Channel('public-chat');
}
public function broadcastAs(): string
{
return 'message.sent';
}
}
Controller
<?php
namespace App\Http\Controllers;
use App\Events\MessageSent;
use Illuminate\Http\Request;
class ChatController extends Controller
{
public function send(Request $request)
{
$request->validate(['message' => 'required|string|max:500']);
broadcast(new MessageSent(
message: $request->message,
username: $request->user()->name ?? 'Anonymous'
));
return response()->json(['status' => 'sent']);
}
}
Vue Component
<script setup>
import { ref, onMounted } from 'vue';
const messages = ref([]);
const newMessage = ref('');
onMounted(() => {
window.Echo.channel('public-chat')
.listen('.message.sent', (event) => {
messages.value.push(event);
});
});
const sendMessage = async () => {
await fetch('/chat/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content },
body: JSON.stringify({ message: newMessage.value })
});
newMessage.value = '';
};
</script>
<template>
<div>
<div v-for="msg in messages" :key="msg.message">
<strong>{{ msg.username }}:</strong> {{ msg.message }}
</div>
<input v-model="newMessage" @keyup.enter="sendMessage" placeholder="Type a message..." />
</div>
</template>
Comparing Reverb with Soketi and Pusher in 2026
The right tool depends on your requirements. Here's how the landscape looks in 2026:
- Laravel Reverb — native PHP, zero external runtime, free, excellent integration with Laravel Broadcasting, Redis support for scaling. Ideal for teams working in the PHP stack. By 2026, it is stable and actively maintained by the Laravel team.
- Soketi — self-hosted, Node.js, Pusher-compatible. Works well, but requires Node.js. Development slowed after Reverb's release, and part of the community has migrated away.
- Pusher — cloud-based, zero maintenance, generous free tier (200 concurrent connections). The go-to choice for startups and MVPs where you don't want to think about infrastructure. The downside: your data goes to an external server, and there are limits and costs as you scale.
- Ably — a more advanced cloud service with delivery guarantees, message history, and a global network. More expensive than Pusher at scale, but offers significantly more capabilities.
Bottom line: if you work in the Laravel stack and want full control over your infrastructure, Reverb is your choice in 2026.
Limitations and When to Choose a Different Tool
Reverb is an excellent tool, but it has limitations you should be aware of:
- Single thread per process. PHP is not Go or Erlang. Despite the event loop, Reverb runs in a single thread. For extreme loads (hundreds of thousands of concurrent connections), careful horizontal scaling with Redis will be required.
- No built-in message history. Reverb does not store message history. If you need missed-message delivery, implement it yourself via a database or choose Ably.
- Presence channel state is not persisted by default. Presence channels are supported, but their state is not preserved across server restarts without Redis.
- WebSocket only. Reverb does not support SSE (Server-Sent Events) or Long Polling as a fallback. If you need support for environments without WebSocket, Laravel Echo with a different transport or Mercure may be a better fit.
- Production workloads require a process supervisor. Reverb should be run under Supervisor or a similar process manager to ensure it restarts automatically if it crashes.
Conclusion
Laravel Reverb in 2026 is a mature, production-ready solution for realtime functionality in PHP applications. It removes the main barrier: no more Node.js, no third-party services, no unnecessary spending on Pusher. You write PHP — Reverb delivers events to clients over WebSocket.
You can get started in 15 minutes: install the package, add the variables to your .env, run php artisan reverb:start — and realtime is working in your Laravel project. From there, add Redis for scaling, Docker and Kubernetes for reliable deployment.
Experiment, build chats, real-time dashboards, live notifications — the tool is ready. The stack stays pure PHP, and the Laravel team actively maintains and develops Reverb. Now is the perfect time to give it a try.
Technologies
Tags
Ruslan Ismailov
Senior Web / Backend Developer. Senior web/backend developer with 9 years of experience. Stack: PHP, Laravel, PostgreSQL, Redis, Docker, Kubernetes, REST, microservices, CI/CD. More about me →