Home/Blog/Engineering

Building Real-Time Features Without the Complexity

February 24, 2026|6 min read|Engineering

CalendarMe has a real-time chat interface. When an invitee shares their available times, the host sees the update immediately — no page refresh needed. This feature was non-negotiable for the user experience we wanted. But implementing it didn't require the architecture you might expect.

What we didn't do

We didn't set up a Redis pub/sub cluster. We didn't implement WebSocket servers with sticky sessions. We didn't add a message queue or event bus. All of those are valid solutions for certain problems, but they weren't necessary for ours.

What we actually did

Server-Sent Events (SSE). That's it. A simple HTTP connection that stays open and streams events from server to client. The browser's built-in EventSource API handles reconnection automatically. No WebSocket library, no socket.io, no third-party real-time service.

Why SSE was enough

Our real-time needs are unidirectional for the most part. The server needs to push updates to the client. The client sends data through normal HTTP requests (submitting availability, confirming times). We don't need full-duplex communication.

SSE also works through CDNs and load balancers without special configuration. WebSockets often require additional infrastructure to proxy correctly. For a small team trying to keep operational complexity low, that matters.

The implementation

A Next.js API route that returns a ReadableStream with the appropriate headers. On the client, an EventSource connection that listens for events and updates React state. Total implementation: about 80 lines of code on the server, 40 on the client.

When a user submits their availability, we write to the database and then notify any open SSE connections for that scheduling session. Simple polling of the database on an interval (every 2 seconds) checks for new updates to stream.

When to reach for something heavier

If we needed: bidirectional real-time communication, thousands of concurrent connections per instance, or sub-100ms latency guarantees — we'd use WebSockets or a managed real-time service. But we don't need those things.

The lesson

Choose the simplest architecture that solves your actual problem. Not the problem you might have someday. Not the problem the conference talk was about. Your problem, today. You can always add complexity later. You can rarely remove it.