EngineeringJul 29, 2026·10 min read

Building Real-Time Features with Supabase Without Melting Your Database

Presence, live cursors, and instant updates are three lines of code — and four ways to accidentally broadcast your whole table.

Muhammad Qitmeer
Muhammad Qitmeer
Co-Founder & CEO, Augere Labs
Share
Presence, live cursors, and instant updates are three lines of code — and four ways to accidentally broadcast your whole table.

Real-time is the feature users notice within five seconds of opening your app. It is also the feature most likely to quietly triple your database load.

Three transports, three jobs

  • postgres_changes — the database tells you a row changed. Correct and durable, but every subscriber costs replication work. Use it for state that must be right.
  • broadcast — ephemeral pub/sub that never touches Postgres. Use it for cursors, typing indicators, and anything you would not mind losing.
  • presence — who is online in a channel. Cheap, but the state syncs to every member, so keep the payload to an id and a display name.

The mistake that shows up at 500 users

Subscribing every client to a whole table. Scope channels to a room, document, or org id and filter server-side. A thousand clients on one unfiltered table subscription means a thousand deliveries per write, and the first symptom is replication lag, not an error.

RLS still applies — and it costs

Realtime evaluates row-level security per subscriber for postgres_changes. Complex policies run on every change for every listener. Keep policies to an indexed column check through a security-definer function, and never let a realtime-heavy table carry a policy with a subquery join.

Batching and throttling

Cursor updates at 60fps will saturate a channel. Throttle client sends to 20–30ms, coalesce rapid database writes with a debounce before persisting, and separate the fast ephemeral path from the durable one.

Reconnection is not optional

Mobile networks drop constantly. On reconnect, refetch canonical state rather than replaying missed events — realtime is a notification channel, not a log. Treat every message as "something changed, go look" and your bugs mostly disappear.

Cost model

Billing tracks concurrent connections and messages. A collaborative editor with 200 concurrent users at 30 messages a second each will dwarf the cost of the rest of your stack, so put ephemeral traffic on broadcast, cap message rates per client, and disconnect idle tabs after a few minutes of no interaction.

FAQ

Frequently asked questions

Should I use postgres_changes or broadcast?+

Broadcast for ephemeral UI signals, postgres_changes for state that must be correct after a refresh. Most apps need both.

Does Realtime respect RLS?+

Yes for postgres_changes, and it evaluates per subscriber — so keep those policies simple and indexed.

How many concurrent connections can it handle?+

Plan-dependent, but the practical limit is usually message volume and RLS cost per change, not raw connection count.

Building something similar?

Let's talk in 30 minutes.

Book an intro
© 2026 Augere Labs