All Playbooks
Databaseintermediate

Building Real-time Features with Supabase

Real-time features sell products, but they also break in spectacular ways if you do not respect the limits of the underlying broker. This playbook is how I add live subscriptions, presence, and optimistic updates to a React app using Supabase, without ending up with a UI that flickers on every reconnection. It covers schema design, RLS, presence, and the patterns that keep real-time work feeling instant rather than fragile.

60 min7 steps
7

Steps

4

Tools

5

Outcomes

intermediate

Difficulty

Technologies used

SupabaseReactTypeScriptPostgreSQL

The methodology

The phases, in order

Each phase below is something I actually run in a project. The descriptions are how I think about the work, not abstract definitions.

01

Phase

Phase 1 of 7

Supabase Project Setup

I create a Supabase project, set strict region locality close to my users, and configure the client with typed responses generated from the database. The service role key never touches the browser. Anything that needs elevated access goes through a server route. Compare alternatives in Supabase vs Firebase.
02

Phase

Phase 2 of 7

Schema with Real-time in Mind

I design tables knowing every column will eventually appear in a realtime payload. That means small rows, no giant JSON blobs in the hot path, and explicit indexes on the columns clients will subscribe by. I enable replication only on the tables that need it, never broadcast everything. The schema sits on top of PostgreSQL with proper foreign keys.
03

Phase

Phase 3 of 7

Row Level Security Policies

RLS is the actual auth layer in Supabase. I write policies before I write a single client query, then test them with a denied-by-default mindset using a non-privileged role. Every table gets at minimum a select and modify policy keyed to the user id or organization id. The API security playbook goes deeper on the threat model.
04

Phase

Phase 4 of 7

Real-time Subscriptions

Subscriptions get set up per component, scoped to the smallest filter that still serves the UI. I always handle the three lifecycle events: subscribed, error, and disconnected. On disconnect I refetch the source of truth before resuming the subscription, otherwise the UI drifts. These are the same primitives used in the real-time blueprint.
05

Phase

Phase 5 of 7

Presence and Cursors

Presence is built on Supabase channels with a short throttle on cursor positions, usually around 50 ms. I store presence state in a React context so multiple components can subscribe without each opening a channel. Stale presence entries get cleaned up on tab close and on a visibility timer to handle the iPhone-in-pocket case.
06

Phase

Phase 6 of 7

Optimistic Updates and Conflict Handling

Optimistic updates make the app feel instant. I apply the change locally, fire the mutation, and reconcile when the server response arrives. For conflicting edits I pick a deterministic resolution, usually last-write-wins keyed by server timestamp, and surface a discreet notice if the user's change got overwritten. See related UI patterns.
07

Phase

Phase 7 of 7

Observability and Failure Modes

Before shipping I add logging around subscribe, unsubscribe, and message receipt. I simulate network drops in dev and verify that the UI recovers without a manual refresh. I also set a sane connection pool size and watch the Supabase dashboard for replication lag, which tells me when I am about to outgrow the default plan.

Results

What You'll Achieve

Expected outcomes from implementing this playbook

Live data synchronization across web and mobile clients
Robust presence indicators that survive network drops
Collaborative editing with predictable conflict resolution
Optimistic UI patterns that hold up under poor connectivity
Want this in your product? Start a project.

Use this playbook

Want me to run this with you?

The playbook is the public version. The private version is me running it for your team against a real deadline. If you have a project on the line, that is usually the faster path.