How to Turn Your Supabase Tables into Live Feeds: Enabling Realtime Subscriptions
Discover how to enable Supabase Realtime on a table, subscribe to live events, and build a real‑time chat UI. Learn the steps, code snippets, and scaling considerations in this practical guide.
14 Aug 2025, 02:49 UTC

The Problem: Polling vs. Push
Most web apps still rely on polling—periodically sending HTTP requests to see if data has changed. Polling wastes bandwidth, introduces latency, and can overwhelm the database if many clients poll at the same interval. Supabase Realtime solves this by turning your PostgreSQL table into a push source: whenever a row is inserted, updated, or deleted, a WebSocket message is broadcast to all subscribed clients.
Step 1 – Make a Table Realtime‑Ready
Supabase uses PostgreSQL’s logical replication to capture changes. For the replication stream to include the full row data, the table must have a REPLICA IDENTITY of FULL (or USING INDEX if you want only the primary key). Without this, UPDATE and DELETE events will miss the old row, limiting what the client can do.
Run the following SQL as a superuser or the table owner. You can execute it in the Supabase dashboard’s SQL editor or via a local client.
ALTER TABLE public.messages REPLICA IDENTITY FULL;
Replace messages with your table name. After this change, the Realtime server will start emitting events for that table.
Step 2 – Subscribe from the Browser
Supabase provides a lightweight JavaScript client that opens a WebSocket to the Realtime server. Below is a minimal snippet that logs every change to the messages table.
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = 'https://your-project.supabase.co';
const supabaseKey = 'PUBLIC_ANON_KEY'; // or SERVICE_ROLE_KEY for admin
const supabase = createClient(supabaseUrl, supabaseKey);
supabase
.channel('public:messages')
.on('postgres_changes', {
event: '*',
schema: 'public',
table: 'messages',
}, payload => {
console.log('Realtime payload:', payload);
// e.g., update UI here
})
.subscribe();
Key points:
channel('public:messages')tells the server which table to watch.- The
event: '*'filter listens to INSERT, UPDATE, and DELETE. - Use the
PUBLIC_ANON_KEYfor client‑side code; for server‑side or privileged operations, use theSERVICE_ROLE_KEY. - Always run this code after the page has loaded; the client will receive events as soon as they are emitted.
Concrete Example: Live Chat
Suppose you have a messages table with columns id, user_id, body, and created_at. When a user sends a message, you insert a row. The Realtime subscription above will push that new row to every connected client, which can then append it to the chat window without a manual refresh.
INSERT INTO public.messages (user_id, body) VALUES (1, 'Hello, world!');
On the client side, the payload will contain new (the inserted row) and old (null for INSERT). You can then render payload.new.body in the UI.
Step 3 – Verify the Flow
To confirm that Realtime is working:
- Run
supabase startlocally or ensure your project is live. - Open the Supabase dashboard → Realtime → Logs. You should see entries for your INSERT, UPDATE, or DELETE.
- Open a browser console on a page that runs the subscription code. Insert a row via SQL or the API; the console should log the payload almost instantly.
Trade‑offs & Scaling Considerations
Realtime pushes are great, but they come with costs:
- WebSocket Connections – Each client holds an open connection. On the free tier, Supabase limits you to 100 concurrent connections per project. Exceeding this will reject new subscriptions.
- Bandwidth & Payload Size – Large columns (e.g.,
JSONBblobs) are sent in full. For high‑frequency writes, consider sending only a reference or using server‑side compression. - Server Load – Logical replication and WebSocket handling consume CPU and memory. For millions of writes per second, you might need to shard your Realtime channel or batch updates.
A common mitigation is to use event: 'INSERT' only if you only care about new rows, or to throttle updates by grouping them server‑side and sending a single change event.
Practical Checklist Before Production
- Run
ALTER TABLE ... REPLICA IDENTITY FULLon every table you want to stream. - Verify that your Realtime logs show the expected events.
- Monitor connection counts via the Supabase dashboard or
supabase status. - Consider using a CDN‑proxied WebSocket endpoint if you have a global audience.
- Test under load: simulate multiple clients and high write rates to observe latency and connection limits.
Wrap‑up
Supabase Realtime turns any PostgreSQL table into a live data source with minimal effort. By setting REPLICA IDENTITY and subscribing via the JavaScript client, you can replace costly polling loops with push‑based updates. Keep an eye on connection limits, payload size, and server load, and you’ll have a responsive, real‑time user experience for any app—chat, dashboards, or collaborative tools.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.