Real-time, without the framework

Live notifications, chat and dashboards that update themselves do not need a heavy platform. Here is the small, boring architecture we use — and why boring is the point.

The moment an app needs to update itself — a notification that arrives, a message that appears, a dashboard number that ticks up without a refresh — teams reach for something big. A real-time platform, a heavy framework, a managed service billed per connection. Usually they don't need it. Here is the small architecture we actually run.

PHP publishes, Go fans out, Redis in between

Our business logic stays in PHP, where it belongs. When something happens worth pushing — a new message, an order update, a metric change — PHP writes one event to a Redis stream. A small, single-purpose Go service consumes that stream and fans the event out over WebSockets to the right connected browsers. That's the whole shape.

The division of labour is deliberate. PHP never holds a socket open; Go never touches the database or the business rules. Each side does the one thing it is good at, and neither becomes a second place where logic lives and drifts.

Auth without leaking a token

A browser proves who it is with a short-lived, single-use ticket, not a long-lived token pasted into a URL where it would leak through logs and history. The ticket is exchanged at the moment of connection and immediately spent. The socket layer never has to know your business — it only has to know it is you.

The rule that keeps it honest

The one discipline that makes this reliable: the socket is an accelerator, never the source of truth. On load, and on every reconnect, the client fetches its current state over normal HTTP — then applies live events on top. If a message is missed during a dropped connection, the next refresh has it. Nothing important exists only as a real-time event.

That rule is why the whole thing can stay small. We don't need the socket layer to guarantee delivery, replay history, or survive every edge case — because HTTP already does. The real-time part is left free to do the one thing it is for: make the update feel instant.

Boring, in infrastructure, is a compliment. A real-time system you rarely have to think about is one built the right size.

More from the blog

All articles