Meetflow: The WebRTC Stack That Treats Disconnection Like a First-Class State

A deep look at a self-hosted video platform that combines mediasoup, Socket.io, Redis, and PostgreSQL to keep rooms alive, hosts in control, and speakers visible.

8 min read • View on GitHub • More from CodeCrusaderr

A wide meeting room is split by a thin bridge of signal lines. One participant fades into a temporary gap while the rest of the room stays intact around a central timer. The image explains the repo's core idea: a disconnected user is not deleted immediately, but held in a grace period so the room can recover cleanly.
Meetflow treats a dropped connection as a temporary state, not an instant exit. That small choice changes how the whole room behaves under stress.
Key Takeaways

The 30-Second Ghost That Makes Meetflow Feel Real

The sharpest idea in Meetflow is also the quietest one. When a participant disconnects, the room does not instantly forget them. The system keeps that user in limbo long enough to reconnect, then cleans up only if they fail to return.

That is a product decision, not just an implementation detail. It protects the conversation from network noise, browser hiccups, and brief tab switches, which is where many real-time apps feel brittle.

This diagram shows why Meetflow feels more like a living room than a transient call. The reconnect window gives the system time to preserve continuity before it commits to cleanup.

What Meetflow Actually Is

Meetflow is a self-hosted video conferencing platform built as a monorepo. The backend is a Node.js and Express service, the frontend is a React app, and the media plane is powered by mediasoup, which means the server forwards media instead of asking every client to talk directly to every other client.

LayerRole in MeetflowWhy it matters
FrontendReact SPA for the room UIKeeps the user experience separate from the media machinery
SignalingSocket.io event bridgeMoves room state and control messages between clients and server
Mediamediasoup SFUHandles multi-party audio and video routing without P2P fan-out
PersistencePostgreSQL and RedisStores durable records and live room state in the right places

That split matters because conferencing is not one problem. Rendering the UI, negotiating sockets, routing media, and remembering who is in the room all fail in different ways. Meetflow keeps those concerns apart instead of flattening them into one pile of event handlers.

Why the Stack Is Split the Way It Is

The backend is organized around domains, not around one giant WebRTC file. Mediasoup owns transport and routing. Socket.io owns signaling and broadcasts. Module code handles meeting and authentication rules. That shape is the first clue that the repo is trying to behave like a product system, not a tutorial.

A close-up chain of audio activity runs through a small observer, then through an event bridge, then lights up a single participant card while others dim. The image explains how low-level media events become visible meeting behavior without coupling the media worker directly to the UI layer.
Active speaker is not a UI trick here. It is a pipeline that translates audio energy into room state and then into interface updates.

This separation is especially clean in the media pipeline. A low-level media worker can detect audio activity, then hand that signal off to a custom event bridge, and only then does the room UI react. That avoids the usual trap where the media layer and the interface become tangled in the same callback soup.

mediasoup Is the Real Engine Room

Meetflow uses mediasoup as an SFU, or Selective Forwarding Unit. In plain terms, the server does not mix everyone's media into one giant stream. It receives streams from clients, decides what each participant should get, and forwards them efficiently.

The repo also scales workers across CPU cores. That is a practical move, because media routing is not cheap. Spreading workers across hardware keeps the server from turning into a single point of pressure as the room fills up.

// Conceptual shape of the mediasoup layer
const workers = Array.from({ length: os.cpus().length }, async () => {
  return await mediasoup.createWorker();
});

// Routers, transports, and observers are then attached per room
// so the media plane stays isolated from signaling and persistence.

The Clean Trick Behind Active Speaker

The most elegant mechanism in the repo is the active-speaker path. mediasoup's audio-level observer detects who is speaking, and the event is then relayed through the app's signaling layer so the room can mark the right participant as active.

That sounds small until you compare it to the alternative. In a sloppier stack, the media worker would know too much about the UI, or the UI would poll for state and guess. Meetflow avoids both problems by making the media event explicit and the product response downstream.

Host Controls Turn a Call Into a Managed Room

Meetflow includes host controls like kick, lock, and force mute. These are not just interface buttons. The server enforces them, which matters because governance should survive a flaky client or a tampered browser session.

Force mute is the clearest example. The server pauses the producer and emits a signal so the client updates its interface. That keeps the control plane authoritative and the user experience coherent at the same time.

ControlWhat it changesWhy server-side enforcement matters
Lock meetingBlocks new joinsPrevents UI-only bypasses
Kick userRemoves a participant from the roomThe room state stays consistent across clients
Force mutePauses a producer and updates the clientThe media plane and the interface agree on the result

The State Model: Cold, Warm, and Hot

Meetflow's architecture becomes easier to understand if you think in temperature tiers. PostgreSQL holds cold, durable records. Redis holds warm, active room metadata. In-memory mediasoup objects hold the hot stuff, the live WebRTC resources that cannot be serialized away without breaking the call.

That is a sensible split. Database rows are for history and identity. Redis is for sessions and ephemeral coordination. In-memory objects are for the live transport graph that only exists while the room is breathing.

State layerExamplesWhy it lives there
PostgreSQLUsers, meetings, reconnect deadlinesNeeds durability and auditability
RedisActive room state, locks, transient metadataNeeds fast reads and short-lived coordination
In-memory mediasoup stateRouters, transports, producersRepresents live media objects that cannot be stored as plain records

Meetflow vs the Usual WebRTC Stack

The contrast is easiest to see against the familiar alternatives. A basic peer-to-peer WebRTC app can be simple, but it gets fragile as rooms grow. A tutorial-grade signaling app can look complete, but it often stops at connection setup and never learns how to govern a room.

CapabilityBasic P2P WebRTCTutorial signaling appMeetflow
Multi-party scalingPoorLimitedBuilt around SFU forwarding
Reconnect behaviorUsually brittleOften manualGrace period with cleanup
Host controlsClient-side at bestUsually absentServer-enforced
Active speaker handlingAd hocOften missingExplicit media-to-UI pipeline
State persistenceMinimalUsually ephemeralPostgreSQL plus Redis plus in-memory media

Meetflow pays for that maturity with complexity. But the payoff is obvious. The room does not collapse the moment one participant blips. The host can actually govern the meeting. The media layer stays separate from the control layer. That is what a productized communication stack looks like.

What This Repo Suggests About Product Maturity

Meetflow still reads as an early project, but it is already thinking like a production system. The code is modular, the media plane is separated from signaling, and the state model respects the difference between durable data, live session data, and ephemeral transport objects.

That is the real takeaway. The repo is not interesting because it sends video. It is interesting because it understands that real-time products need memory, governance, and recovery, not just packets.