Development

Building Real-Time SaaS Applications with Laravel 11

How to add live updates to a Laravel SaaS app with Laravel Reverb, broadcasting and Echo, and how to run WebSockets reliably in production.

Vishal Shah

5 min read

Users now expect software to update without refreshing the page. A new support ticket appears in the queue straight away. A colleague's comment shows up while you are reading. A dashboard counter ticks up as orders arrive. This is what people mean by a real-time application.

Laravel 11 made real-time features much easier to build by introducing Laravel Reverb, a first-party WebSocket server, and a single command to set up broadcasting. Everything in this guide also applies to later Laravel versions. We will cover how real-time features work in Laravel, how to build one, and how to run it reliably in production.

Key takeaways

  • Laravel sends real-time updates through events, broadcasting and WebSockets.
  • Laravel Reverb is Laravel's own WebSocket server, so you do not need a paid third-party service.
  • Private and presence channels control who receives each update.
  • Reverb can scale across several servers using Redis.

How real-time works in Laravel

A normal web page asks the server for data. A real-time page keeps a connection open, called a WebSocket, so the server can push updates to it the moment something changes. In Laravel, that flow has four parts:

  • An event in your application, such as TicketCreated or OrderShipped.
  • Broadcasting, which sends that event to a channel.
  • A WebSocket server, such as Laravel Reverb, which holds the open connections and delivers the message.
  • Laravel Echo, a JavaScript library in the browser that listens to channels and updates the page.

Setting up Reverb

In Laravel 11 and later, one Artisan command installs broadcasting, Reverb and the Echo configuration:

php artisan install:broadcasting

You then start the WebSocket server with:

php artisan reverb:start

Reverb uses the same protocol as Pusher, so Laravel Echo and most existing broadcasting code work with it unchanged. If you would rather not run your own WebSocket server, hosted services such as Pusher and Ably work with the same Laravel code.

Broadcasting your first event

To broadcast an event, implement the ShouldBroadcast interface and say which channel it goes to. Here, a new support ticket is sent to everyone on that company's support team:

class TicketCreated implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(public Ticket $ticket) {}

    public function broadcastOn(): array
    {
        return [new PrivateChannel('teams.'.$this->ticket->team_id.'.tickets')];
    }

    public function broadcastWith(): array
    {
        return [
            'id' => $this->ticket->id,
            'subject' => $this->ticket->subject,
            'priority' => $this->ticket->priority,
        ];
    }
}

broadcastWith() controls exactly which fields are sent. Keep it small, and never send data the receiving users should not see. In the browser, Echo listens for the event and updates the list:

Echo.private('teams.' + teamId + '.tickets')
    .listen('TicketCreated', (ticket) => addTicketToQueue(ticket));

Broadcast events are queued by default, so sending them does not slow down the request that triggered them. Make sure your queue workers are running.

Control who can listen

In a SaaS product, security is the most important part of real-time features. Laravel has three kinds of channel:

  • Public channels can be joined by anyone. Use them only for data that is truly public.
  • Private channels require the user to be logged in and authorised. You write the rule in routes/channels.php.
  • Presence channels are private channels that also show who else is connected, which is useful for "who's online" lists and showing that someone else is editing a record.

The authorisation rule for the channel above checks that the user belongs to that team:

Broadcast::channel('teams.{teamId}.tickets', function (User $user, int $teamId) {
    return $user->team_id === $teamId;
});

In a multi-tenant app, include the tenant or team in every channel name and check it in every rule. A missing check here means one customer could receive another customer's updates.

Real-time features worth building

  • Live queues and inboxes for support and sales teams, so nobody works from an out-of-date list
  • Notifications that appear as soon as something needs attention
  • Progress updates for long-running jobs such as imports and exports
  • Live dashboards for orders, calls or sign-ups
  • Presence and collaboration, such as showing who is viewing a record
  • Chat and comments inside your product

Not everything needs to be real-time. If a report is only checked once a day, a normal page load is simpler and cheaper. Save WebSockets for places where seeing a change straight away helps users work faster.

Running Reverb in production

A WebSocket server is a long-running process that keeps thousands of connections open, which is different from a normal PHP request. The Reverb documentation covers this in detail. The main points are:

  • Use a process manager such as Supervisor to keep Reverb running, and restart it with php artisan reverb:restart when you deploy new code.
  • Put it behind a reverse proxy such as Nginx, which handles SSL and passes WebSocket traffic to Reverb.
  • Raise connection limits. Each connection uses an open file on the server, so the operating system, Nginx and Supervisor limits often need increasing.
  • Install the ext-uv extension if you expect more than about 1,000 connections at once. Reverb's default event loop is limited to around 1,024 open files.
  • Scale across servers with Redis. Set REVERB_SCALING_ENABLED=true and point every Reverb server at the same Redis server. Messages received by one server are then shared with the others, and a load balancer spreads connections between them.
  • Monitor connections with Laravel Pulse, which has built-in cards for Reverb connections and messages.

Handle dropped connections

Mobile users lose signal, laptops go to sleep and servers restart. Echo reconnects automatically, but any events sent while a user was disconnected are missed. Design for this: when the connection comes back, reload the current state from your API rather than assuming nothing changed. For anything important, such as a new order, the database should always be the source of truth, with real-time updates simply keeping the screen fresh.

Frequently asked questions

What is Laravel Reverb?

Reverb is Laravel's first-party WebSocket server. It lets a Laravel application push real-time updates to browsers without using a paid third-party service, and it works with Laravel's existing broadcasting tools and Laravel Echo.

Do I need Pusher for real-time features in Laravel?

No. Since Laravel 11 you can run Reverb yourself. Pusher and Ably are still good options if you prefer a hosted service and do not want to manage WebSocket servers.

Can Laravel handle thousands of real-time users?

Yes, with the right setup. Reverb can run on several servers behind a load balancer, sharing messages through Redis, and server limits can be raised to support many open connections.

We build real-time Laravel SaaS applications, from live support queues to dashboards, and our own products use real-time technology every day. See our Laravel development services or send us your project details below.

Vishal Shah

Vishal Shah

Technical Adviser, Renav Limited

Vishal has 13+ years of experience in full-stack software development, specialising in Laravel, Next.js and cloud architecture. He leads technical direction at Renav Limited, a UK-based bespoke software agency.

Start a project

Tell us what you're building

Share a few lines about your project and we'll come back with a clear plan and a free quote. No obligation, no hard sell.

Vishal Shah, Technical Adviser at Renav Limited

Your enquiry goes to Vishal Shah

Technical Adviser · replies within 2 business hours

Get your free quote

No obligation. We only use your details to reply to this enquiry. Privacy notice