Comparisons

Supabase vs Firebase: AI Rules for Each BaaS

Supabase is PostgreSQL-based with SQL queries and Row Level Security. Firebase is document-based with NoSQL and security rules. Each needs different AI rules for database access, auth, storage, real-time, and security patterns.

8 min read·May 5, 2025

from().select().eq() in Firebase = undefined. collection().where() in Supabase = wrong API entirely.

PostgreSQL vs Firestore, SQL vs NoSQL queries, RLS vs security rules, auth, and rule templates

SQL BaaS vs NoSQL BaaS

Supabase is an open-source Firebase alternative built on PostgreSQL. You get: a full Postgres database (SQL queries, joins, foreign keys, JSONB, PostGIS), Row Level Security for authorization, a client library with real-time subscriptions, authentication with multiple providers, edge functions (Deno-based serverless), and file storage with CDN. Supabase's philosophy: give developers a real database with BaaS convenience. You own the data model; Supabase provides the infrastructure.

Firebase is Google's BaaS platform built on proprietary infrastructure. Firestore: a document-based NoSQL database (collections and documents, no joins, denormalized data). Firebase Auth: authentication with Google, email, phone, and social providers. Cloud Storage: file storage with security rules. Cloud Functions: Node.js serverless functions. Firebase's philosophy: zero-to-production in hours with a fully managed, opinionated stack. You follow Firebase patterns; Firebase handles everything.

Without BaaS-specific rules: AI generates SQL queries for Firebase (Firestore has no SQL), uses Firestore collection references in Supabase (Supabase uses table queries), applies Firebase security rules to Supabase (Supabase uses Postgres RLS), or writes Cloud Functions patterns for Supabase Edge Functions (different runtimes and APIs). The BaaS choice determines every data access, auth, and security pattern. One rule prevents every platform-crossing error.

ℹ️ Open Source vs Proprietary

Supabase: open-source, self-hostable, PostgreSQL you can take anywhere. Firebase: proprietary Google, data lives in Google Cloud. Supabase: if you outgrow the BaaS, you have a standard Postgres database. Firebase: migration requires rewriting every query for a different database.

Database Access: SQL Queries vs Document References

Supabase database access: SQL-like client API on top of PostgREST. const { data, error } = await supabase.from('users').select('id, name, email').eq('role', 'admin').order('created_at', { ascending: false }). The API maps to SQL: SELECT id, name, email FROM users WHERE role = 'admin' ORDER BY created_at DESC. Joins: .select('*, posts(title, created_at)') generates a JOIN. You can also use raw SQL via supabase.rpc() for stored procedures. AI rule: 'Supabase: use client.from(table).select().eq().order(). Joins via foreign key references in select(). Complex queries: rpc() for stored procedures.'

Firebase Firestore access: document-based references. const snapshot = await db.collection('users').where('role', '==', 'admin').orderBy('createdAt', 'desc').get(). Data is denormalized: no joins. To get a user with their posts: two separate queries (get user, then get posts where userId matches). Or: embed posts inside the user document (denormalized, reads are fast, writes update the parent). AI rule: 'Firebase: collection().doc() or collection().where(). No joins — denormalize data or run multiple queries. Subcollections for nested data.'

The database rule is the most impactful: AI generating .from('users').select('*, posts(*)') in Firebase = API does not exist (Firestore has no joins). AI generating collection('users').where() in Supabase = wrong API entirely. The data access pattern is platform-determined: Supabase = relational (joins, foreign keys, SQL). Firebase = document (collections, denormalization, subcollections). One rule aligns every query.

  • Supabase: supabase.from('table').select().eq().order() — SQL-like, joins via select()
  • Firebase: db.collection('col').where().orderBy().get() — document-based, no joins
  • Supabase: relational model with foreign keys and JOINs
  • Firebase: denormalized documents, subcollections, multiple queries for related data
  • AI error: join syntax in Firebase = undefined. collection() in Supabase = wrong API
💡 Joins Exist vs Joins Do Not Exist

Supabase: .select('*, posts(title)') generates a SQL JOIN. Get user + posts in one query. Firebase Firestore: no joins. Get user, then get posts in a separate query. Or denormalize: embed posts in the user document. The data model paradigm (relational vs document) determines every query pattern.

Authentication: Supabase Auth vs Firebase Auth

Supabase Auth: built-in authentication with: email/password, magic links, OAuth providers (Google, GitHub, Discord), phone/SMS, and SAML SSO (enterprise). Client: const { data, error } = await supabase.auth.signInWithOAuth({ provider: 'google' }). Session management: Supabase handles JWT tokens, refresh, and session storage. User data: stored in auth.users table, accessible via RLS policies. AI rule: 'Supabase auth: supabase.auth.signInWithOAuth/signInWithPassword/signUp. Session: automatic JWT management. User in auth.users table. RLS policies reference auth.uid().'

Firebase Auth: built-in authentication with: email/password, phone, OAuth providers (Google, Apple, Facebook, Twitter, GitHub), anonymous auth, and custom tokens. Client: const result = await signInWithPopup(auth, googleProvider). Session: Firebase manages ID tokens, refresh tokens, and auth state persistence. User data: auth.currentUser or onAuthStateChanged listener. AI rule: 'Firebase auth: signInWithPopup/signInWithEmailAndPassword/createUserWithEmailAndPassword. State: onAuthStateChanged listener. User: auth.currentUser. Security rules reference request.auth.uid.'

The auth rule prevents: AI using signInWithPopup in Supabase (Firebase API), using supabase.auth.signUp in Firebase (Supabase API), or referencing auth.uid() in Firebase security rules (Firebase uses request.auth.uid). The auth APIs look similar conceptually but differ in every method name and state management pattern. One rule about which auth API to use prevents every authentication integration error.

Security: Row Level Security vs Security Rules

Supabase security: PostgreSQL Row Level Security (RLS). Policies are SQL: CREATE POLICY user_own_data ON profiles FOR ALL USING (auth.uid() = user_id). RLS runs at the database level: every query is filtered by the policy, regardless of which client or API accesses the data. Policies reference: auth.uid() (the authenticated user ID), auth.role() (the user role), and any column in the table. AI rule: 'Supabase security: enable RLS on every table. Policies: CREATE POLICY with USING clause. Reference auth.uid() for user-scoped access. RLS is SQL — full Postgres expression power.'

Firebase security: Firestore Security Rules. Rules are a custom DSL: rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /profiles/{userId} { allow read, write: if request.auth != null && request.auth.uid == userId; } } }. Rules run at the Firestore level: every read/write is checked against the rules. Rules reference: request.auth (the authenticated user), resource.data (the existing document), and request.resource.data (the incoming data). AI rule: 'Firebase security: firestore.rules file. match paths for collections and documents. request.auth.uid for user-scoped access. Rules are a custom DSL, not SQL.'

The security rule prevents: AI writing SQL RLS policies for Firebase (Firebase uses a custom DSL, not SQL), writing Firebase match/allow rules for Supabase (Supabase uses SQL CREATE POLICY), or referencing request.auth in Supabase (Supabase uses auth.uid()). Security misconfiguration is the highest-risk BaaS error. One rule about which security model to use prevents data exposure from malformed security policies.

  • Supabase: PostgreSQL RLS, SQL-based policies, auth.uid() for user identity
  • Firebase: Firestore Security Rules, custom DSL, request.auth.uid for user identity
  • Supabase RLS: runs at database level — even direct API access is filtered
  • Firebase rules: runs at Firestore level — client SDK and REST API both checked
  • Security misconfiguration is the highest-risk BaaS error — one rule prevents exposure
⚠️ Security Misconfiguration = Data Exposure

SQL RLS policy for Firebase: syntax does not exist. Firebase match/allow for Supabase: wrong DSL entirely. Security rules in the wrong format = no security at all. This is the highest-risk BaaS error. One rule about which security model prevents data exposure from malformed policies.

Real-Time and Storage

Supabase real-time: subscribe to database changes via WebSocket. const channel = supabase.channel('room1').on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'messages' }, (payload) => { addMessage(payload.new); }).subscribe(). Real-time is: database-driven (Postgres logical replication), event-typed (INSERT/UPDATE/DELETE), and table-scoped. Also: Broadcast (send messages to all subscribers) and Presence (track who is online). AI rule: 'Supabase real-time: channel.on("postgres_changes", config, callback). Events: INSERT/UPDATE/DELETE. Presence for online users.'

Firebase real-time: Firestore onSnapshot listener. const unsubscribe = onSnapshot(collection(db, 'messages'), (snapshot) => { snapshot.docChanges().forEach(change => { if (change.type === 'added') addMessage(change.doc.data()); }); }). Real-time is: document-driven (Firestore change streams), change-typed (added/modified/removed), and query-scoped (the listener filters match the initial query). Also: Firebase Realtime Database (separate product, JSON-based, simpler but less powerful). AI rule: 'Firebase real-time: onSnapshot on collection/doc references. Changes: added/modified/removed. Query-scoped: listener respects where/orderBy.'

Storage follows the same pattern: Supabase Storage uses the same API style (supabase.storage.from('bucket').upload/download), Firebase Cloud Storage uses a different API (ref(storage, path), uploadBytes, getDownloadURL). The storage rule is less critical than database and auth (simpler APIs) but still platform-specific. AI generating Firebase storage refs in Supabase or Supabase bucket API in Firebase produces wrong function calls.

Ready-to-Use Rule Templates

Supabase CLAUDE.md template: '# BaaS (Supabase). Database: PostgreSQL via supabase.from(table).select().eq(). Auth: supabase.auth.signInWithOAuth/signUp/signInWithPassword. Security: RLS on every table, CREATE POLICY with auth.uid(). Real-time: channel.on("postgres_changes", config, callback). Storage: supabase.storage.from(bucket).upload/download. Edge Functions: Deno runtime. Types: generate with supabase gen types. Never Firebase patterns (collection, onSnapshot, security rules DSL, signInWithPopup).'

Firebase CLAUDE.md template: '# BaaS (Firebase). Database: Firestore via collection().doc().get()/set()/where(). Auth: signInWithPopup/signInWithEmailAndPassword/createUserWithEmailAndPassword. Security: firestore.rules with match/allow DSL, request.auth.uid. Real-time: onSnapshot on collection/doc. Storage: ref(storage, path), uploadBytes, getDownloadURL. Functions: Cloud Functions (Node.js). Never Supabase patterns (from().select(), RLS policies, auth.uid(), postgres_changes).'

The templates draw a clear BaaS boundary. Every API method name is platform-specific: from() vs collection(), auth.signInWithOAuth vs signInWithPopup, postgres_changes vs onSnapshot. The negative rules prevent the most dangerous errors: security policies in the wrong format (data exposure) and auth methods from the wrong platform (login broken). Copy the template for your BaaS.

Comparison Summary

Summary of Supabase vs Firebase AI rules.

  • Database: Supabase = PostgreSQL (SQL, joins, RLS) vs Firebase = Firestore (NoSQL, denormalized, subcollections)
  • Queries: supabase.from().select().eq() vs db.collection().where().get()
  • Auth: supabase.auth.signInWithOAuth vs signInWithPopup(auth, provider)
  • Security: Supabase RLS (SQL policies, auth.uid()) vs Firebase rules (custom DSL, request.auth.uid)
  • Real-time: Supabase postgres_changes (database events) vs Firebase onSnapshot (document changes)
  • Open source: Supabase = yes (self-hostable) vs Firebase = proprietary Google
  • SQL power: Supabase supports: joins, stored procedures, PostGIS, full-text search via Postgres
  • Templates: every method name is platform-specific — mixing produces undefined function errors