Why I Ditched NoSQL for Everything
Firebase basically single-handedly taught me how to put an app into production. Back in the day, spinning up a Firestore database and watching data sync instantly on my phone felt like magic. I shipped dozens of projects with firebase-admin and firebase/firestore. But over the years, as my platforms (like XRide Labs) scaled, that magic started feeling more like a straightjacket.
Enter Supabase. Here's a raw, honest look at why I made the switch and why I believe PostgreSQL wrapped in an open-source BaaS (Backend-as-a-Service) is the undisputed champion for modern React and Next.js apps heading into 2026.
1. The Nightmare of Complex Queries in Firestore
In Firestore, data modeling requires you to think backward. If you want to show a user their latest 10 rides and the names of the drivers, you have two bad choices:
- Duplicate the driver's name on the
ridesdocument (Denormalization). Now you have to write a cloud function to update every ride if a driver changes their name. - Fetch the 10 rides, map over them, and run 10 separate queries to fetch the drivers. Your "cheap" no-SQL structure just cost you 11 read operations.
With Supabase, you just write a relational JOIN using their powerful JS client.
// It's this simple to fetch rides with their associated drivers
const { data: rides, error } = await supabase
.from("rides")
.select(
`
id,
pickup_location,
dropoff_location,
driver:drivers (
id,
name,
rating
)
`,
)
.eq("user_id", currentUserId)
.order("created_at", { ascending: false })
.limit(10);One query. One network request. Clean, typed data. The developer experience gap here is immense.
2. Row Level Security > Security Rules
Firebase Security Rules always felt like writing pseudo-code in a weird text editor inside a web console. Testing them was a pain, and maintaining them across environments required messy JSON files.
Supabase utilizes pure PostgreSQL Row Level Security (RLS). It's written in SQL, it executes precisely where your data lives, and it's incredibly robust.
-- Allow users to only view their own rides
CREATE POLICY "Users can view own rides"
ON rides
FOR SELECT
USING ( auth.uid() = user_id );
-- Allow users to insert rides only if they are authenticated
CREATE POLICY "Users can create rides"
ON rides
FOR INSERT
WITH CHECK ( auth.uid() = user_id );If you ever query SELECT * FROM rides from the client, the DB doesn't just block you; it filters the results based on the JWT token. You only get back the rows you own. No more WHERE used_id == auth.uid() required in the client code!
3. The Power of Postgres Functions and Triggers
Firestore Cloud Functions are essentially Node.js scripts running on Google Cloud. They suffer from agonizing cold starts if traffic drops, and they add extra latency to database writes since the DB has to trigger an external HTTP/PubSub event.
In Supabase, you can run logic directly inside the database using Postgres Functions and Triggers written in PL/pgSQL. Need to automatically update a user's total ride count every time a new ride is inserted? Just write a trigger.
CREATE OR REPLACE FUNCTION increment_ride_count()
RETURNS TRIGGER AS $$
BEGIN
UPDATE users
SET total_rides = total_rides + 1
WHERE id = NEW.user_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER on_ride_inserted
AFTER INSERT ON rides
FOR EACH ROW EXECUTE FUNCTION increment_ride_count();This executes instantly. No cold starts, no network hops between a Node.js server and a DB.
4. Automatic TypeScript Types
With Firebase, ensuring my Firestore documents match my React components meant manually writing TypeScript interfaces and hoping I didn't break anything.
With Supabase, you can generate types directly from your database schema using the CLI:
npx supabase gen types typescript --project-id my-project > types/supabase.ts
When I type supabase.from('users').update({ name: 'Krithik' }), my IDE knows exactly what columns exist and what data types they expect. This feature alone saves me hours of unforced errors.
Final Verdict
Firebase is still an incredible tool for MVPs, rapid prototyping, and pure simple document stores. But when building the XRide Labs umbrella, the relational complexity required a SQL backend.
Supabase gives me the scale and strict rules of PostgreSQL combined with the "plug-and-play" realtime DX of Firebase. If you haven't tried it in your Next.js stack yet, you are seriously missing out.