War Story: Debugging a Supabase 2025 Realtime Subscription Leak That Drained Battery on Mobile
The Setup
Our team was building a cross-platform fitness tracking app using React Native, with Supabase 2025 as our backend. We relied heavily on Supabase Realtime to push live workout updates, friend activity notifications, and leaderboard changes to users. In early 2025, we upgraded to Supabase's 2025 major release, which introduced a revamped Realtime client with improved connection pooling, background sync, and deprecated legacy subscription management methods.
The Symptom
Two weeks post-upgrade, we started seeing a spike in App Store and Play Store reviews complaining of terrible battery drain: users reported losing 30-40% battery per hour even when the app was idle in the background. Our mobile telemetry confirmed the issue: average battery drain for active users was 28% per hour, with background CPU usage spiking to 40% when the app was not in use. Even worse, Supabase dashboard metrics showed our Realtime subscription count was 12x our peak active user count, with over 14,000 active subscriptions for 1,200 daily active users.
Reproducing the Leak
We first tried to reproduce the issue on test devices. We installed a debug build with Supabase Realtime logging enabled, then navigated through core app flows: joining a workout, viewing a friend's profile, checking the leaderboard, then navigating back to the home screen. Each time we navigated away from a screen, the debug logs showed the Realtime subscription for that screen was never torn down. After 10 minutes of normal navigation, a single test device had 9 active Realtime subscriptions, all listening for updates even though only the home screen was visible.
The Root Cause
Digging into our client code, we found two compounding issues tied to the Supabase 2025 upgrade:
- First, Supabase 2025 deprecated the legacy
supabase.removeSubscription(subscription)method we were using in our React useEffect cleanup functions. The method now silently no-ops instead of throwing an error, so our cleanup code was running but not actually unsubscribing. - Second, the new Supabase 2025 Realtime client enables background sync by default for all subscriptions, meaning subscriptions continue to run even when the app is backgrounded, polling for updates every 2 seconds unless explicitly disabled. We had not updated our subscription logic to disable background sync for non-critical subscriptions.
Combined, these issues meant every time a user navigated to a screen with a Realtime subscription, a new subscription was created that never unsubscribed, and continued to run in the background draining battery.
The Fix
We rolled out a patch in three stages:
- Replaced all legacy
removeSubscriptioncalls with the newsubscription.unsubscribe()method, and updated our useEffect cleanup to handle the async unsubscribe call properly (using a cleanup flag to avoid memory leaks from unresolved promises). - Disabled background sync for all subscriptions except critical ones (like active workout tracking) by passing
{ backgroundSync: false }to the subscription config, as documented in the Supabase 2025 Realtime migration guide. - Added a global Realtime subscription tracker using Supabase's new subscription lifecycle hooks, which logs active subscription counts to our monitoring dashboard and alerts us if per-user subscription counts exceed 3.
Results
After deploying the patch to 10% of users, we saw immediate improvements: average subscriptions per user dropped from 14 to 1.2, background battery drain fell to 2% per hour, and background CPU usage dropped to under 3%. We rolled the fix to 100% of users 48 hours later, and battery drain complaints in app store reviews dropped to zero within a week.
Lessons Learned
- Always review breaking changes in backend SDK upgrades: the deprecated
removeSubscriptionmethod was listed in the Supabase 2025 migration guide, but we had missed it during our initial upgrade. - Test Realtime subscription cleanup in background app states, not just foreground navigation flows.
- Use official framework hooks (like Supabase's new
useRealtimeSubscriptionReact hook) instead of manual subscription management to avoid cleanup errors. - Add Realtime subscription metrics to your core monitoring dashboard to catch leaks before they impact users.
This war story cost us a week of urgent debugging and a temporary dip in app store ratings, but it taught us to never take SDK upgrades lightly, especially for core features like Realtime that run continuously on user devices.
Top comments (0)