Source:
ocean/docs/adr/0033-realtime-subscriptions.md| ✏️ Edit on GitHub
0033. Supabase Realtime Subscriptions for Live Updates
Date: 2025-08-14
Status
Accepted
Context
Our billing and organization pages required users to manually refresh to see updates such as:
- Subscription status changes
- Payment method additions
- Invoice generation
- Provisioning completion
This led to:
- Poor user experience during critical operations
- Support tickets about "missing" updates
- Users repeatedly refreshing pages
- Confusion during collaborative billing management
Decision
We implemented Supabase Realtime subscriptions to push live updates to the UI without polling or manual refreshes.
Implementation Approach
- Generic Hook:
useRealtimeSubscriptionfor any table/filter combination - Specific Hooks: Pre-configured subscriptions for common use cases
- Automatic Query Invalidation: Updates trigger React Query cache refreshes
- Type-Safe: Full TypeScript support for payload types
Example Usage
// Generic subscription
useRealtimeSubscription({
table: 'organizations',
event: 'UPDATE',
filter: `id=eq.${orgId}`,
onUpdate: (payload) => {
console.log('Org updated:', payload.new)
},
invalidateQueries: [['organization', orgId]],
})
// Specialized hook
useSubscriptionStatusSubscription(orgId)
Subscriptions Implemented
- Organization Updates: Plan changes, billing info
- Subscription Status: Active, canceled, past due
- Invoice Creation: New invoices appear instantly
- Payment Methods: Added/removed cards
- Provisioning Events: Resource creation status
Consequences
Positive
- Real-time UX: Changes appear instantly across all tabs/users
- Reduced Server Load: No polling required
- Collaborative: Multiple users see same updates
- Event-Driven: Natural fit for billing events
- Efficient: Only subscribes to relevant data
Negative
- WebSocket Connections: Additional connection management
- Debugging Complexity: Harder to trace data flow
- State Synchronization: Must handle connection drops
Performance Impact
- Polling requests: Eliminated (was ~1req/5sec/user)
- Time to see updates: 5-30 seconds → <100ms
- User satisfaction: Significant improvement in billing workflows
Alternatives Considered
-
Polling
- Rejected: Inefficient, poor UX
-
Server-Sent Events
- Rejected: Less flexible than WebSockets
-
Manual Refresh Only
- Rejected: Poor user experience
Implementation Details
- Subscriptions are request-scoped (cleanup on unmount)
- Automatic reconnection on connection loss
- Query invalidation triggers UI updates
- Filtered subscriptions reduce unnecessary updates
Best Practices
- Subscribe only to data visible on screen
- Use filters to minimize updates
- Combine with optimistic updates for best UX
- Handle connection state in critical flows
- Log but don't crash on subscription errors