Skip to content
Realtime

Reverb, Soketi or Pusher: Picking Your WebSocket Server

One protocol, three servers, one reversible decision: what managed Pusher buys, what Reverb and Soketi cost to operate, and the connection-count crossover math that settles it.

4 min read Updated Sep 3, 2026
Reverb, Soketi or Pusher: Picking Your WebSocket Server

Every team that ships the Pusher integration eventually opens the invoice, looks at the connection count, and asks the same question: "couldn't we just… host this ourselves?" Since Laravel Reverb landed as a first-party WebSocket server, the answer changed from "carefully" to "quite possibly" — but the decision has more dimensions than the invoice. Having run all three setups in production (Pusher, Soketi, Reverb), here's the real comparison.

Managed Pusher versus self-hosted Reverb/Soketi: protocol compatibility, cost and operations

The beautiful accident: one protocol, three servers

The strategic fact underlying everything: Reverb and Soketi both speak the Pusher protocol. Same Echo client, same channel auth, same event format — switching is an env-file change, not a rewrite:

# The entire migration, application-side:
BROADCAST_CONNECTION=reverb        # was: pusher
REVERB_APP_ID=...
REVERB_APP_KEY=...
REVERB_APP_SECRET=...
# Echo config points at your host instead of Pusher's cluster. Done.

This means the decision is reversible — which should immediately lower everyone's blood pressure. Start managed, move self-hosted when the bill justifies it, move back if ops hurt. The seam is free; use it.

Option 1: Pusher (managed)

What you're buying: zero ops, global edge presence, connection scaling you never think about, a debug console, and someone else's 3 a.m. Genuinely excellent at all of it.
What it costs: per-connection pricing that's friendly at hundreds and eye-watering at scale — the jump tiers land around concurrent connections, and "every open browser tab is a connection" means a modestly popular dashboard hits five figures of concurrency fast. Also: your realtime traffic transits a third party (a compliance conversation in some industries), and message size/rate limits are theirs, not yours.
Right when: early product, small team, connection counts in the hundreds-to-low-thousands, or realtime is garnish rather than core.

Option 2: Reverb (first-party, self-hosted)

Reverb is Laravel's own server — PHP, but on ReactPHP's event loop, so it holds tens of thousands of concurrent connections per instance without the PHP-can't-do-sockets caveats of old. The pitch: first-party integration (config, Echo, docs all aligned), one php artisan reverb:start process under Supervisor, and horizontal scaling via a Redis pub/sub backplane when one box stops being enough. Runs happily in the same Kubernetes cluster as everything else.
The honest caveats: it's the youngest of the three — the sharp edges are fewer each release, but you are the ops team now: TLS termination, process supervision, capacity planning, and the multi-node scaling questions are yours. Budget real load-testing before the marketing launch, not after.
Right when: Laravel shop, meaningful connection counts, comfort running your own services — the sweet spot where the Pusher bill exceeds a small server plus a slice of your attention.

Option 3: Soketi (self-hosted, battle-hardened)

Soketi predates Reverb as the self-hosted Pusher replacement: Node/uWebSockets under the hood, ferociously fast, memory-frugal, with per-app limits and metrics endpoints that betray its "run this for many tenants" heritage. It's boring in the best way — I have Soketi instances that have survived multiple Laravel major versions without a config change.
Trade-offs: it's a separate non-PHP service (fine in Docker, one more image to track), and its development pace has slowed since Reverb absorbed the ecosystem's attention — factor maintenance trajectory into a long-lived choice.
Right when: you want self-hosted today with maximum battle-testing, you're multi-tenant, or you're not exclusively a Laravel shop (it serves any Pusher-protocol client).

The decision, with numbers where it hurts

Concurrent connections   Recommendation
─────────────────────────────────────────────────────────────
< ~500                   Pusher. The bill is lunch money; ship features.
500 – 5,000              The crossover zone. Compare Pusher tier vs.
                         one $40 VPS + Reverb + your Tuesday afternoons.
> 5,000                  Self-host (Reverb if Laravel-native appeals,
                         Soketi if maturity does) — with monitoring,
                         load tests, and a Redis backplane plan.
Compliance-sensitive     Self-host regardless of count; traffic stays home.
Realtime IS the product  Self-host, and read the scaling post twice.

Three parting rules. Keep the reconcile-on-reconnect pattern from the integration post no matter which server — self-hosting changes who drops the connection, not whether. Load-test with realistic connection counts, not message counts — sockets die by concurrency, and 10k idle connections stress a server differently than 100 chatty ones. And instrument from day one: connections, messages/sec, memory per node on a dashboard — because the managed provider's graphs are the one thing you genuinely gave up.

Sitting inside that 500–5,000 crossover zone with an invoice in one hand? That's a one-afternoon analysis — I'll bring the spreadsheet.

Keep reading

Related articles

Realtime 5 min read

Scaling WebSockets Past One Box

Sockets are tenants, not confetti: the pub/sub backplane, stateless nodes and rolling drains, the reconnect stampede and its jittered cure, missed-message recovery by data shape, and the capacity cliffs to test first.