The old gap
If you have built Laravel apps for a while, you know the pattern: broadcasting existed, but the websocket server was often Pusher, Soketi, or a custom Node process. That worked. It also meant another moving part to deploy and monitor.
What Reverb is
Laravel Reverb is a first-party WebSocket server that speaks the Pusher protocol and plugs into Laravel Echo. For notifications, presence channels, live dashboards, and “something changed—refresh this panel” UX, it is enough for many products I ship. Product page: reverb.laravel.com.
Step 1 — Install broadcasting (includes Reverb)
On modern Laravel (11+ / 13), install with:
php artisan install:broadcasting
Behind the scenes this runs Reverb setup with sensible defaults (publishes config, sets env keys, wires broadcasting). Prefer the official docs for your exact Laravel version if the prompt options change.
Step 2 — Environment
After install you should have values similar to:
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=...
REVERB_APP_KEY=...
REVERB_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}"
In production, REVERB_HOST / scheme / port should match what the browser uses (often your public domain on 443 behind a reverse proxy), while the Reverb process may listen on an internal port like 8080.
Step 3 — Start Reverb locally
php artisan reverb:start
Default listen is typically 0.0.0.0:8080. After code/config changes in a long-running process, use php artisan reverb:restart so connections drain cleanly (especially under Supervisor).
Step 4 — Broadcast an event
php artisan make:event OrderShipped --queued
Implement ShouldBroadcast (or ShouldBroadcastNow for immediate), define broadcastOn() channels, then event(new OrderShipped($order));. Keep a queue worker running if events are queued—silent “nothing broadcasts” is often a queue problem, not a websocket problem.
Step 5 — Echo on the frontend
With Vite + Laravel Echo configured for Reverb (install scaffolding usually sets this up), subscribe in JS:
Echo.private(`orders.${orderId}`)
.listen('OrderShipped', (e) => {
console.log(e);
});
Authorize private/presence channels in routes/channels.php.
Production checklist
- Run Reverb under Supervisor/systemd as a supervised long-running process
- Reverse proxy WebSockets; Reverb expects traffic for
/app(WS) and/apps(API) when proxied—see the Nginx examples in the official docs - Use TLS at the edge (
REVERB_SCHEME=https, port 443 publicly) - Scale horizontally with Redis pub/sub when one server is not enough (documented scaling section)
- Monitor connection counts; default event loops have practical connection limits—read the docs before assuming “unlimited”
Where I still respect Node
Large chat platforms, collaborative editors, game sockets, or teams already deep in Socket.io may still want a dedicated Node realtime service. Reverb is a credible first-party answer for common Laravel realtime needs—not a claim that Node stopped existing.
Troubleshooting (the failures I actually see)
- Events never arrive: queued broadcast but no
queue:workprocess; orShouldBroadcastNowexpected but not used. - Echo connects then dies in production: reverse proxy missing WebSocket upgrade headers; or public
REVERB_HOST/SCHEMEstill point at localhost. - Private channel 403:
routes/channels.phpauthorization fails; user not authenticated to the broadcasting auth endpoint. - Works locally, fails on HTTPS site: mixed content—page is https but Echo tries ws://.
- Config changed but behavior did not: long-running Reverb process needs
reverb:restart.
Minimal Nginx sketch (conceptual)
Proxy /app and /apps to the internal Reverb port and enable WebSocket upgrade headers. Copy the exact snippet from the current Reverb production docs for your Nginx version—proxy snippets go stale if you invent them from memory.
Supervisor sketch
[program:reverb]
command=php /var/www/app/artisan reverb:start
user=www-data
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/reverb.log
Adjust user/paths to your server. Pair with a queue worker program similarly.
When Reverb is the wrong tool
If the product is the realtime layer—thousands of rooms, custom binary protocols, game ticks—I evaluate dedicated Node (or other) infrastructure honestly. Reverb shines when Laravel already owns the domain and you need broadcasts, presence, and notifications without leaving the ecosystem.
Security notes for channels
Never put secrets in broadcast payloads the browser should not see. Authorize private channels every time. Treat presence channel data as public to everyone in the room.