Laravel Reverb: Channels, Auth &amp; Scaling in Production | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. Laravel Reverb WebSocket Broadcasting: Real-Time Channels, Auth, and Scaling Patterns

 Laravel Reverb WebSocket Broadcasting: Real-Time Channels, Auth, and Scaling Patterns
======================================================================================

 Go beyond the hello-world demo: learn how to structure private and presence channels, lock down authorization, tune Reverb's server config, and scale horizontally with Redis pub/sub in production.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 2 Jul 2026 · Updated 2 Jul 2026 · 4 min read

ShareCopy linkCopied

 ![Laravel Reverb WebSocket Broadcasting: Real-Time Channels, Auth, and Scaling Patterns](https://cdn.msaied.com/345/e17d357902124a7017fb076e5e19fb14.png) 

  On this page +1. [Beyond the Hello-World: Laravel Reverb in Production](#beyond-the-hello-world-laravel-reverb-in-production)
2. [Channel Types and When to Use Each](#channel-types-and-when-to-use-each)
3. [Defining Private and Presence Channels](#defining-private-and-presence-channels)
4. [Broadcasting an Event on a Presence Channel](#broadcasting-an-event-on-a-presence-channel)
5. [Tuning the Reverb Server](#tuning-the-reverb-server)
6. [Horizontal Scaling with Redis Pub/Sub](#horizontal-scaling-with-redis-pubsub)
7. [Client-Side Authentication Flow](#client-side-authentication-flow)
8. [Key Takeaways](#key-takeaways)

 Beyond the Hello-World: Laravel Reverb in Production
----------------------------------------------------

Laravel Reverb ships as a first-party WebSocket server, but most tutorials stop at `php artisan reverb:start` and a public channel. Real applications need private channels with proper authorization, presence channels for collaborative UIs, and a deployment story that survives more than one server.

### Channel Types and When to Use Each

| Channel | Auth required | Presence data | Typical use | |---------|--------------|---------------|-------------| | Public | No | No | Public feeds, announcements | | Private | Yes | No | Per-user notifications, order updates | | Presence| Yes | Yes | Collaborative editors, live cursors |

### Defining Private and Presence Channels

Channel routes live in `routes/channels.php`. Return `true`/`false` for private channels; return an array of user metadata for presence channels — Reverb forwards that payload to every subscriber.

```php
// routes/channels.php

use App\Models\Project;
use Illuminate\Support\Facades\Broadcast;

// Private: only the owning user may subscribe
Broadcast::channel('orders.{orderId}', function ($user, int $orderId) {
    return $user->orders()->where('id', $orderId)->exists();
});

// Presence: return metadata so the UI knows who is online
Broadcast::channel('projects.{projectId}', function ($user, int $projectId) {
    $project = Project::find($projectId);

    if (! $project?->members()->where('user_id', $user->id)->exists()) {
        return false;
    }

    return [
        'id'     => $user->id,
        'name'   => $user->name,
        'avatar' => $user->avatar_url,
    ];
});

```

### Broadcasting an Event on a Presence Channel

```php
// app/Events/CursorMoved.php

use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class CursorMoved implements ShouldBroadcast
{
    public function __construct(
        public readonly int   $projectId,
        public readonly int   $userId,
        public readonly float $x,
        public readonly float $y,
    ) {}

    public function broadcastOn(): array
    {
        return [new PresenceChannel("projects.{$this->projectId}")];
    }

    // Only broadcast the payload the client actually needs
    public function broadcastWith(): array
    {
        return ['user_id' => $this->userId, 'x' => $this->x, 'y' => $this->y];
    }

    // Throttle: drop duplicate events within the same second
    public function broadcastWhen(): bool
    {
        return true; // add cache-based throttle here if needed
    }
}

```

### Tuning the Reverb Server

Reverb's config lives in `config/reverb.php`. The most impactful knobs for production:

```php
'servers' => [
    'reverb' => [
        'host'    => env('REVERB_SERVER_HOST', '0.0.0.0'),
        'port'    => env('REVERB_SERVER_PORT', 8080),
        'options' => [
            // Raise open-file limits before touching this
            'max_connections'  => 10_000,
            // Keep idle connections alive; lower = faster cleanup
            'max_request_size' => 10_000, // bytes
        ],
    ],
],

```

Pair this with a systemd unit that sets `LimitNOFILE=65535` so the OS doesn't cap you first.

### Horizontal Scaling with Redis Pub/Sub

A single Reverb process is a single point of failure. Run multiple workers behind a load balancer and let Redis fan out messages between them:

```php
// config/reverb.php  (scaling section)
'scaling' => [
    'enabled' => true,
    'driver'  => 'redis',
    'connection' => env('REVERB_SCALING_CONNECTION', 'default'),
],

```

Each Reverb worker subscribes to the same Redis channel. When worker A receives a broadcast, Redis delivers it to workers B and C so their connected clients all receive the event — no sticky sessions required.

> **Tip:** Use a dedicated Redis connection for Reverb scaling, separate from your cache and queue connections, to avoid head-of-line blocking under load.

### Client-Side Authentication Flow

Echo's auth endpoint hits `/broadcasting/auth` by default. Ensure your API middleware group includes `auth:sanctum` (or your guard of choice) and that CORS allows the origin your frontend runs on:

```javascript
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

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,
    forceTLS: false,
    enabledTransports: ['ws'],
    authEndpoint: '/broadcasting/auth',
});

window.Echo
    .join(`projects.${projectId}`)
    .here(members  => console.log('online:', members))
    .joining(member => console.log('joined:', member))
    .leaving(member => console.log('left:',   member))
    .listen('CursorMoved', e => moveCursor(e));

```

### Key Takeaways

- **Private channels** return a boolean; **presence channels** return a metadata array — both go through `routes/channels.php`.
- Keep `broadcastWith()` lean; every connected client receives the full payload.
- Enable Redis scaling before you need it — retrofitting under load is painful.
- Separate the Reverb Redis connection from cache/queue to prevent contention.
- Set OS-level file descriptor limits (`LimitNOFILE`) before raising `max_connections`.

- [laravel](https://www.msaied.com/public/articles?search=laravel)
- [reverb](https://www.msaied.com/public/articles?search=reverb)
- [websockets](https://www.msaied.com/public/articles?search=websockets)
- [broadcasting](https://www.msaied.com/public/articles?search=broadcasting)
- [real-time](https://www.msaied.com/public/articles?search=real-time)

 Frequently asked questions 
---------------------------

  Do I need sticky sessions when running multiple Reverb workers behind a load balancer?No. With Redis scaling enabled, each worker subscribes to a shared Redis pub/sub channel. A broadcast published to any worker is fanned out to all workers, so any client can connect to any worker without session affinity.

   How does Reverb's channel authorization differ from a standard HTTP middleware check?Channel authorization runs through the `/broadcasting/auth` endpoint, which invokes the closure registered in `routes/channels.php`. The closure receives the authenticated user and any route parameters extracted from the channel name, letting you perform Eloquent queries or policy checks just as you would in a controller.

   What is the practical difference between ShouldBroadcast and ShouldBroadcastNow?ShouldBroadcast dispatches the broadcast through your queue, so it respects queue workers and backpressure. ShouldBroadcastNow bypasses the queue and broadcasts synchronously during the HTTP request — useful for low-latency events where queue delay is unacceptable, but it adds latency to the originating request.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

[Mohamed Said](https://www.msaied.com/public#person)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articlePHP 8.3+ Typed Enums, Backed Casts, and Readonly Properties in Modern Laravel](https://www.msaied.com/public/articles/php-83-typed-enums-backed-casts-and-readonly-properties-in-modern-laravel) [Next articleLaravel AI Tasks: AI Orchestration with Queues, Logging, and Cost Control](https://www.msaied.com/public/articles/laravel-ai-tasks-ai-orchestration-with-queues-logging-and-cost-control)  

   On this page
-------------

1. [Beyond the Hello-World: Laravel Reverb in Production](#beyond-the-hello-world-laravel-reverb-in-production)
2. [Channel Types and When to Use Each](#channel-types-and-when-to-use-each)
3. [Defining Private and Presence Channels](#defining-private-and-presence-channels)
4. [Broadcasting an Event on a Presence Channel](#broadcasting-an-event-on-a-presence-channel)
5. [Tuning the Reverb Server](#tuning-the-reverb-server)
6. [Horizontal Scaling with Redis Pub/Sub](#horizontal-scaling-with-redis-pubsub)
7. [Client-Side Authentication Flow](#client-side-authentication-flow)
8. [Key Takeaways](#key-takeaways)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
