Tell us what you're building. We'll come back with a plan.
Realtime Without Pain: The Supabase Channels Playbook

The Realtime Tax Most Teams Ignore
Building a custom WebSocket layer is one of those tasks that looks small in the estimate and absorbs three engineers for two months in reality. Connection management, reconnection logic, auth, scaling out across pods, fanning messages to the right subscribers, dealing with backpressure—each of these is a project on its own.
For 90% of "we need realtime" requirements, you don't need a custom layer. You need a battle-tested abstraction that handles the boring parts for you, and your team focused on the actual product.
Channels vs Custom WebSockets
Supabase Channels give you three flavors of realtime out of the box:
- Postgres changes—subscribe to inserts, updates, and deletes on any table with a row-level filter
- Broadcast—pub/sub messaging on arbitrary channel names, no database round-trip
- Presence—who-is-here state synced across all clients in a channel
We mix these on every project. Postgres changes for canonical state (order status, dashboard rows). Broadcast for ephemeral events (typing indicators, cursor positions). Presence for "who's online right now."
The setup is one line on the server (RLS policy gates who can subscribe) and one hook on the client. The first time we shipped this in production, the engineer who built it said "wait, is that it" out loud. Yes. That's it.
Presence Is the Killer Feature
Most teams underestimate how much warmth presence adds to a product. Showing avatars of who else is viewing the same document, or which teammate is editing a specific row, turns a transactional UI into a collaborative one without any deep architectural changes.
We've shipped presence into project management tools, support consoles, and operations dashboards. Every time, it's the feature users mention first when they describe the new product to colleagues. Cost to implement: a few hundred lines of code.
Auth in Realtime
The most common failure mode we see in homegrown WebSocket layers is auth drift. The user logs out in tab A but tab B still has an open socket with the old token. The socket happily streams events the user shouldn't see anymore.
Supabase Channels reuse the project's auth tokens, RLS policies, and JWT rotation logic. When the token rotates, the channel re-authenticates. When the user signs out, the socket closes. We get the full Postgres-RLS security model on the live wire without writing a single new policy.
Performance Ceilings We've Hit
This isn't free magic. We've hit two hard ceilings in production:
1. About 10k concurrent subscribers on a single channel. Past that, Supabase's hosted realtime starts dropping messages. The fix is to shard channels by tenant or geography.
2. About 5k Postgres-change events per second across the project. This is the WAL replication ceiling. For higher throughput we route hot events through Broadcast instead of Postgres changes.
For the vast majority of products we ship—B2B SaaS with hundreds to low-thousands of simultaneous users—these ceilings are not even visible. If your product genuinely needs millions of concurrent users, you'll know it before you start and you'll budget for a custom layer accordingly.
A Real Example
One of our clients runs a multi-tenant operations platform with about 800 simultaneous operators across 60 organizations. They wanted "live dashboards"—status changes, new orders, alerts, all visible without a page refresh.
We shipped it in nine days. Six hours of setup, four days of UI polish, two days of edge-case testing, and a day of load testing. The total infrastructure cost increase: $0. They were already on Supabase, and Realtime is included.
The lesson is not that Supabase is magic. It's that the boring abstraction over WebSockets is solved well enough that you should not be building your own unless you've ruled it out for a specific, measurable reason.
Mark P.
đź’» Writes about software at LevelByte. Built things at startups and agencies for the last decade.
Tell us what you're building. We'll come back with a plan.
Realtime Without Pain: The Supabase Channels Playbook

The Realtime Tax Most Teams Ignore
Building a custom WebSocket layer is one of those tasks that looks small in the estimate and absorbs three engineers for two months in reality. Connection management, reconnection logic, auth, scaling out across pods, fanning messages to the right subscribers, dealing with backpressure—each of these is a project on its own.
For 90% of "we need realtime" requirements, you don't need a custom layer. You need a battle-tested abstraction that handles the boring parts for you, and your team focused on the actual product.
Channels vs Custom WebSockets
Supabase Channels give you three flavors of realtime out of the box:
- Postgres changes—subscribe to inserts, updates, and deletes on any table with a row-level filter
- Broadcast—pub/sub messaging on arbitrary channel names, no database round-trip
- Presence—who-is-here state synced across all clients in a channel
We mix these on every project. Postgres changes for canonical state (order status, dashboard rows). Broadcast for ephemeral events (typing indicators, cursor positions). Presence for "who's online right now."
The setup is one line on the server (RLS policy gates who can subscribe) and one hook on the client. The first time we shipped this in production, the engineer who built it said "wait, is that it" out loud. Yes. That's it.
Presence Is the Killer Feature
Most teams underestimate how much warmth presence adds to a product. Showing avatars of who else is viewing the same document, or which teammate is editing a specific row, turns a transactional UI into a collaborative one without any deep architectural changes.
We've shipped presence into project management tools, support consoles, and operations dashboards. Every time, it's the feature users mention first when they describe the new product to colleagues. Cost to implement: a few hundred lines of code.
Auth in Realtime
The most common failure mode we see in homegrown WebSocket layers is auth drift. The user logs out in tab A but tab B still has an open socket with the old token. The socket happily streams events the user shouldn't see anymore.
Supabase Channels reuse the project's auth tokens, RLS policies, and JWT rotation logic. When the token rotates, the channel re-authenticates. When the user signs out, the socket closes. We get the full Postgres-RLS security model on the live wire without writing a single new policy.
Performance Ceilings We've Hit
This isn't free magic. We've hit two hard ceilings in production:
1. About 10k concurrent subscribers on a single channel. Past that, Supabase's hosted realtime starts dropping messages. The fix is to shard channels by tenant or geography.
2. About 5k Postgres-change events per second across the project. This is the WAL replication ceiling. For higher throughput we route hot events through Broadcast instead of Postgres changes.
For the vast majority of products we ship—B2B SaaS with hundreds to low-thousands of simultaneous users—these ceilings are not even visible. If your product genuinely needs millions of concurrent users, you'll know it before you start and you'll budget for a custom layer accordingly.
A Real Example
One of our clients runs a multi-tenant operations platform with about 800 simultaneous operators across 60 organizations. They wanted "live dashboards"—status changes, new orders, alerts, all visible without a page refresh.
We shipped it in nine days. Six hours of setup, four days of UI polish, two days of edge-case testing, and a day of load testing. The total infrastructure cost increase: $0. They were already on Supabase, and Realtime is included.
The lesson is not that Supabase is magic. It's that the boring abstraction over WebSockets is solved well enough that you should not be building your own unless you've ruled it out for a specific, measurable reason.
Mark P.
đź’» Writes about software at LevelByte. Built things at startups and agencies for the last decade.
Realtime Without Pain: The Supabase Channels Playbook

The Realtime Tax Most Teams Ignore
Building a custom WebSocket layer is one of those tasks that looks small in the estimate and absorbs three engineers for two months in reality. Connection management, reconnection logic, auth, scaling out across pods, fanning messages to the right subscribers, dealing with backpressure—each of these is a project on its own.
For 90% of "we need realtime" requirements, you don't need a custom layer. You need a battle-tested abstraction that handles the boring parts for you, and your team focused on the actual product.
Channels vs Custom WebSockets
Supabase Channels give you three flavors of realtime out of the box:
- Postgres changes—subscribe to inserts, updates, and deletes on any table with a row-level filter
- Broadcast—pub/sub messaging on arbitrary channel names, no database round-trip
- Presence—who-is-here state synced across all clients in a channel
We mix these on every project. Postgres changes for canonical state (order status, dashboard rows). Broadcast for ephemeral events (typing indicators, cursor positions). Presence for "who's online right now."
The setup is one line on the server (RLS policy gates who can subscribe) and one hook on the client. The first time we shipped this in production, the engineer who built it said "wait, is that it" out loud. Yes. That's it.
Presence Is the Killer Feature
Most teams underestimate how much warmth presence adds to a product. Showing avatars of who else is viewing the same document, or which teammate is editing a specific row, turns a transactional UI into a collaborative one without any deep architectural changes.
We've shipped presence into project management tools, support consoles, and operations dashboards. Every time, it's the feature users mention first when they describe the new product to colleagues. Cost to implement: a few hundred lines of code.
Auth in Realtime
The most common failure mode we see in homegrown WebSocket layers is auth drift. The user logs out in tab A but tab B still has an open socket with the old token. The socket happily streams events the user shouldn't see anymore.
Supabase Channels reuse the project's auth tokens, RLS policies, and JWT rotation logic. When the token rotates, the channel re-authenticates. When the user signs out, the socket closes. We get the full Postgres-RLS security model on the live wire without writing a single new policy.
Performance Ceilings We've Hit
This isn't free magic. We've hit two hard ceilings in production:
1. About 10k concurrent subscribers on a single channel. Past that, Supabase's hosted realtime starts dropping messages. The fix is to shard channels by tenant or geography.
2. About 5k Postgres-change events per second across the project. This is the WAL replication ceiling. For higher throughput we route hot events through Broadcast instead of Postgres changes.
For the vast majority of products we ship—B2B SaaS with hundreds to low-thousands of simultaneous users—these ceilings are not even visible. If your product genuinely needs millions of concurrent users, you'll know it before you start and you'll budget for a custom layer accordingly.
A Real Example
One of our clients runs a multi-tenant operations platform with about 800 simultaneous operators across 60 organizations. They wanted "live dashboards"—status changes, new orders, alerts, all visible without a page refresh.
We shipped it in nine days. Six hours of setup, four days of UI polish, two days of edge-case testing, and a day of load testing. The total infrastructure cost increase: $0. They were already on Supabase, and Realtime is included.
The lesson is not that Supabase is magic. It's that the boring abstraction over WebSockets is solved well enough that you should not be building your own unless you've ruled it out for a specific, measurable reason.
Mark P.
đź’» Writes about software at LevelByte. Built things at startups and agencies for the last decade.
Tell us what you're building. We'll come back with a plan.
Realtime Without Pain: The Supabase Channels Playbook

The Realtime Tax Most Teams Ignore
Building a custom WebSocket layer is one of those tasks that looks small in the estimate and absorbs three engineers for two months in reality. Connection management, reconnection logic, auth, scaling out across pods, fanning messages to the right subscribers, dealing with backpressure—each of these is a project on its own.
For 90% of "we need realtime" requirements, you don't need a custom layer. You need a battle-tested abstraction that handles the boring parts for you, and your team focused on the actual product.
Channels vs Custom WebSockets
Supabase Channels give you three flavors of realtime out of the box:
- Postgres changes—subscribe to inserts, updates, and deletes on any table with a row-level filter
- Broadcast—pub/sub messaging on arbitrary channel names, no database round-trip
- Presence—who-is-here state synced across all clients in a channel
We mix these on every project. Postgres changes for canonical state (order status, dashboard rows). Broadcast for ephemeral events (typing indicators, cursor positions). Presence for "who's online right now."
The setup is one line on the server (RLS policy gates who can subscribe) and one hook on the client. The first time we shipped this in production, the engineer who built it said "wait, is that it" out loud. Yes. That's it.
Presence Is the Killer Feature
Most teams underestimate how much warmth presence adds to a product. Showing avatars of who else is viewing the same document, or which teammate is editing a specific row, turns a transactional UI into a collaborative one without any deep architectural changes.
We've shipped presence into project management tools, support consoles, and operations dashboards. Every time, it's the feature users mention first when they describe the new product to colleagues. Cost to implement: a few hundred lines of code.
Auth in Realtime
The most common failure mode we see in homegrown WebSocket layers is auth drift. The user logs out in tab A but tab B still has an open socket with the old token. The socket happily streams events the user shouldn't see anymore.
Supabase Channels reuse the project's auth tokens, RLS policies, and JWT rotation logic. When the token rotates, the channel re-authenticates. When the user signs out, the socket closes. We get the full Postgres-RLS security model on the live wire without writing a single new policy.
Performance Ceilings We've Hit
This isn't free magic. We've hit two hard ceilings in production:
1. About 10k concurrent subscribers on a single channel. Past that, Supabase's hosted realtime starts dropping messages. The fix is to shard channels by tenant or geography.
2. About 5k Postgres-change events per second across the project. This is the WAL replication ceiling. For higher throughput we route hot events through Broadcast instead of Postgres changes.
For the vast majority of products we ship—B2B SaaS with hundreds to low-thousands of simultaneous users—these ceilings are not even visible. If your product genuinely needs millions of concurrent users, you'll know it before you start and you'll budget for a custom layer accordingly.
A Real Example
One of our clients runs a multi-tenant operations platform with about 800 simultaneous operators across 60 organizations. They wanted "live dashboards"—status changes, new orders, alerts, all visible without a page refresh.
We shipped it in nine days. Six hours of setup, four days of UI polish, two days of edge-case testing, and a day of load testing. The total infrastructure cost increase: $0. They were already on Supabase, and Realtime is included.
The lesson is not that Supabase is magic. It's that the boring abstraction over WebSockets is solved well enough that you should not be building your own unless you've ruled it out for a specific, measurable reason.
Mark P.
đź’» Writes about software at LevelByte. Built things at startups and agencies for the last decade.
Tell us what you're building. We'll come back with a plan.


