Networking Fundamentals' own domain taught WebSockets as a general bidirectional-connection mechanism. Supabase Realtime is a specific, concrete application of that mechanism — and the genuinely interesting part is what feeds it: not a custom event system, but Postgres's own replication mechanism, repurposed.
3 min read
// Naive: poll the database every few seconds
setInterval(async () => {
const { data } = await supabase.from("messages").select("*");
updateUI(data);
}, 3000);Polling works, but wastes real database load checking for changes that usually haven't happened, and introduces a real latency floor (up to the polling interval) before a genuine change is even noticed — exactly the kind of inefficiency this curriculum's own caching and message-queue domains have already named in other contexts. A genuinely better mechanism should push a change to clients the instant it happens, not make every client ask repeatedly whether anything changed.
Every write to a Postgres database is already recorded in its Write-Ahead Log (WAL) — a durability mechanism that exists regardless of Realtime, used for crash recovery. Logical replication is a real Postgres feature that streams a readable, structured version of WAL changes to a subscriber — Supabase Realtime is, underneath, exactly this: a service subscribed to your database's own logical replication stream, forwarding each change over WebSocket connections (Networking Fundamentals' own mechanism) to every client that's subscribed to that specific table or row.
supabase
.channel("messages-channel")
.on("postgres_changes", { event: "INSERT", schema: "public", table: "messages" },
(payload) => addMessageToUI(payload.new)
)
.subscribe();Because Realtime reads directly from a mechanism Postgres already maintains for its own durability guarantees, there's no separate "also publish an event" step application code needs to remember — lesson 2's entire point (enforcement the database itself guarantees, not something application code has to remember) shows up again here in a different shape: a row changing is the event, with no risk of a write succeeding while the corresponding "something changed" notification gets forgotten, the way a hand-rolled pub/sub layer bolted onto application code genuinely can.
A Realtime subscription doesn't bypass Row Level Security — a client subscribed to a table only receives change notifications for rows its own RLS policies (lesson 2) would actually let it read via a normal query. This is exactly the kind of subtle correctness property worth stating explicitly: Realtime is a different transport for data a client could access, not a separate, parallel access-control surface that might accidentally leak more than the REST API does.
A live chat, a collaborative document's cursor positions, a dashboard that should update the instant underlying data changes — these genuinely benefit from Realtime's push model. A typical CRUD page that a user navigates to and reads once has no real need for a live subscription at all; reaching for Realtime by default, rather than for the specific cases that actually need "update live, right now," adds real client-side complexity (managing subscriptions, connection state) for data that a normal request/response fetch would have served just as well.
Check your understanding
A quick comprehension check — not tracked, not graded, just for you.
1. What does Supabase Realtime actually read from, under the hood?
2. Does subscribing to Realtime changes bypass a table's RLS policies?
3. When does reaching for Realtime add unnecessary complexity rather than real benefit?
Supabase