The naive approach to notifications is polling. Every 5 seconds, the client sends a request to the server asking "do I have any new notifications?" The server queries the database, returns the results, and the client updates the UI. This works for a prototype. It does not work at scale.
Consider a workspace with 20 active users, each polling every 5 seconds. That is 240 database queries per minute just for notifications. Now multiply by the number of tables they might want changes from -- notifications, comments, deal updates, @mentions. You are looking at 1,000+ unnecessary queries per minute, most of which return zero results. The database is doing real work to tell you that nothing happened.
Polling is asking "are we there yet?" every five seconds for the entire car ride. WebSockets are the GPS telling you when you have arrived.
SalesSheet runs on Supabase, which includes a Realtime service built on top of PostgreSQL's logical replication. When a row is inserted, updated, or deleted in any table with Realtime enabled, Supabase broadcasts the change to all subscribed clients over a WebSocket connection. No polling required.
Our notification architecture uses three Supabase Realtime channels:
Each user subscribes to a channel filtered by their user ID. When a notification row is inserted into the notifications table with their user ID as the recipient, they receive the payload instantly. The channel filter ensures users only receive their own notifications, enforced by Row Level Security (RLS) on the Supabase side.
All users in a workspace share a broadcast channel for workspace-wide events: new deals created, contacts imported, reports generated. These are not personal notifications -- they are ambient awareness events that keep the team in sync. We use Supabase's broadcast feature (not database changes) for these, because they are ephemeral and do not need to be stored.
Supabase Realtime includes a Presence feature that tracks which users are currently online. We use this to show green dots next to team members' avatars in the sidebar and to display "Sarah is viewing this contact" indicators when two users are looking at the same record. Presence syncs automatically -- when a user closes their browser tab, Supabase detects the WebSocket disconnection and removes them from the presence state.
Our @mention system is the most notification-heavy feature in SalesSheet. Users can @mention teammates in comments on contacts, deals, and activities. When someone types @sarah in a comment, we need to:
The parsing happens client-side for the autocomplete dropdown (so users see suggestions as they type), but the actual mention extraction and notification creation happens server-side in a Supabase Edge Function. This prevents users from spoofing mentions by manipulating the client payload.
When a user types @ in a comment field, we show a dropdown of workspace members. The dropdown filters as they type, using a fuzzy search that matches against first name, last name, and email. We pre-fetch the workspace member list on app load and cache it in memory, so the autocomplete is instant with no network request. The selected mention is rendered as a styled chip in the comment editor, using a contenteditable div with custom mention nodes.
Receiving a notification is only half the problem. Displaying it effectively is the other half. We use a toast notification system that appears in the bottom-right corner of the screen (bottom-center on mobile). Our toast system has specific design rules:
WebSocket connections are fragile. Networks switch, laptops sleep, browsers crash. When the Supabase Realtime connection drops, we need to recover gracefully without missing any notifications. Our reconnection strategy works in three steps:
The disconnection timestamp is tracked using a lastSeen variable that updates every time we receive a Realtime event. If no events arrive for 30 seconds, we send a heartbeat ping. If the ping fails, we know the connection is dead and start the reconnection process before the user even notices.
After migrating from polling to Supabase Realtime, our numbers changed dramatically:
The latency improvement is the one users actually feel. When a teammate @mentions you, the toast appears before they have finished typing their next sentence. That immediacy transforms comments from an asynchronous communication channel into something that feels closer to a real-time chat. Teams that use @mentions heavily report that SalesSheet feels more like Slack than a traditional CRM, which is exactly the experience we wanted.
Real-time is not about technology. It is about team flow. When notifications arrive instantly, conversations happen in the CRM instead of in a separate chat app. Context stays where it belongs -- attached to the deal.