I needed live updates for a large number of users at the same time. Both tools promised it. Only one delivered.
When I started building Spindare's feed, I needed realtime updates. Post like counts updating live, new posts appearing without a pull-to-refresh, activity indicators showing who's online. Both Supabase and Firebase offer this. I tested both properly before committing to one.
This isn't a sponsored comparison. I'm not going to tell you one is objectively better. I'm going to tell you what I found when I actually used them for the specific thing I needed: a high-activity social feed with live updates.
I built the same feed feature twice, once with each backend. Same React Native front end, same data shape, same test conditions. The test was: 200 simultaneous clients all subscribed to the same feed, receiving live updates when posts were liked or commented on. I ran this on a Saturday afternoon from my machine, using k6 for the load simulation.
Firebase was faster on initial connection. Firestore's client SDK is heavily optimised for cold start: a new listener is active within milliseconds. Supabase's Realtime is slightly slower on the first subscription because it goes through a PostgreSQL trigger pipeline.
For subsequent updates, both were effectively instant from a user perspective, sub-100ms in both cases from the point of database write to the point of client notification. This difference is not something users would notice.
This is where the tests diverged. Firebase handled the 200 concurrent clients without complaint. Supabase on the free plan started dropping connections around 150 simultaneous subscribers. I had to implement reconnection logic on the client.
On the Pro plan, Supabase handled 200 concurrent clients reliably. The free tier's connection limit is real and it bites at social app scale earlier than you'd expect.
// Supabase reconnection logic we had to add
const channel = supabase.channel('feed')
.on('system', { event: 'disconnect' }, () => {
console.log('Supabase disconnected, reconnecting...');
setTimeout(() => channel.subscribe(), 2000);
})
.subscribe();This is where Supabase won for me decisively. Spindare's data is relational. Posts have users. Comments have posts and users. Likes are a join table. Leaderboards need aggregations.
With Supabase I write real SQL and get real query power. Pagination, filtering, sorting, aggregations in a single query, all with proper indexes. With Firebase I'm denormalising data, duplicating fields across documents, and writing fan-out functions in Cloud Functions every time I need something that SQL handles in two lines.
โThe moment you need a leaderboard, Firebase stops being fun.โ
Every Firebase developer at some point
I spent about four hours trying to build Spindare's weekly points leaderboard in Firestore without server-side aggregation. It required a Cloud Function running every five minutes to pre-compute the rankings and store them in a separate collection. With Supabase it was one query with a GROUP BY and an index.
Supabase's RLS is more powerful than Firebase's security rules, but significantly harder to write correctly. Firebase security rules are declarative and relatively readable. Supabase RLS policies are SQL, expressive and fast, but easy to write a policy that accidentally blocks everything or allows too much.
I broke our RLS configuration three times during development before I fully understood the model. Firebase security rules took an afternoon to learn properly.
I chose Supabase for Spindare, and I don't regret it. The relational model was the deciding factor. For a social app where you need aggregations, joins, and real queries, Postgres is the right foundation. Firestore would have required increasingly complex workarounds as the data model grew.
If your data has relationships (users own posts, posts have comments, comments have likes), use a relational database. Forcing relational data into a document model creates complexity that compounds over time.
Written by
Kristian Gjergji
Developer ยท Kosovo / Italy