En 2025, Supabase s'affirme comme l'alternative open-source à Firebase. PostgreSQL vs Firestore, Row Level Security vs Rules, pricing transparent vs complexe : découvrez quel Backend-as-a-Service correspond à vos besoins.
🚀 Vue d'Ensemble
Firebase : L'écosystème Google
Firebase domine le marché BaaS depuis 2014 avec son intégration Google Cloud et sa simplicité d'utilisation.
Points forts :
- Firestore (NoSQL temps réel)
- Authentication complète
- Cloud Functions
- Hosting gratuit
- Intégration Google Analytics
- SDKs matures (15+ plateformes)
Supabase : L'alternative open-source
Supabase, lancé en 2020, propose une alternative basée sur PostgreSQL avec philosophie open-source.
Points forts :
- PostgreSQL (SQL relationnelle)
- Row Level Security (RLS)
- Real-time subscriptions
- Auto-generated REST APIs
- Edge Functions (Deno)
- Self-hosting possible
💡 Base de Données : PostgreSQL vs Firestore
Supabase (PostgreSQL)
// Supabase: SQL relationnel avec types forts
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
'https://your-project.supabase.co',
'your-anon-key'
);
// Typage automatique avec CLI
type User = Database['public']['Tables']['users']['Row'];
// Queries SQL-like avec TypeScript
const { data: users, error } = await supabase
.from('users')
.select(`
id,
name,
email,
posts (
id,
title,
created_at
)
`)
.eq('age', 30)
.order('created_at', { ascending: false })
.limit(10);
// Transactions complexes possibles
const { data, error } = await supabase.rpc('transfer_funds', {
from_account: 123,
to_account: 456,
amount: 100
});
// Fonctions PostgreSQL custom
// SQL:
// CREATE FUNCTION transfer_funds(from_account INT, to_account INT, amount DECIMAL)
// RETURNS JSON AS $$
// BEGIN
// UPDATE accounts SET balance = balance - amount WHERE id = from_account;
// UPDATE accounts SET balance = balance + amount WHERE id = to_account;
// RETURN json_build_object('success', true);
// END;
// $$ LANGUAGE plpgsql;
Firebase (Firestore)
// Firebase: NoSQL document-oriented
import { initializeApp } from 'firebase/app';
import { getFirestore, collection, query, where, getDocs, orderBy, limit } from 'firebase/firestore';
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
// Queries NoSQL (moins flexibles que SQL)
const usersRef = collection(db, 'users');
const q = query(
usersRef,
where('age', '==', 30),
orderBy('createdAt', 'desc'),
limit(10)
);
const snapshot = await getDocs(q);
const users = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}));
// Sous-collections (pas de JOIN natif)
const userDoc = doc(db, 'users', userId);
const postsRef = collection(userDoc, 'posts');
const postsSnapshot = await getDocs(postsRef);
// Transactions
await runTransaction(db, async (transaction) => {
const fromDoc = await transaction.get(doc(db, 'accounts', '123'));
const toDoc = await transaction.get(doc(db, 'accounts', '456'));
const newFromBalance = fromDoc.data().balance - 100;
const newToBalance = toDoc.data().balance + 100;
transaction.update(doc(db, 'accounts', '123'), { balance: newFromBalance });
transaction.update(doc(db, 'accounts', '456'), { balance: newToBalance });
});
Comparaison données
| Critère | Supabase (PostgreSQL) | Firebase (Firestore) |
|---|---|---|
| Type | SQL relationnel | NoSQL document |
| JOINs | ✅ Natif | ❌ Application-side |
| Transactions | ✅ ACID complet | ⚠️ Limité (500 docs) |
| Queries complexes | ✅ SQL complet | ⚠️ Limitations |
| Typage | ✅ Fort (PostgreSQL) | ⚠️ Flexible |
| Migrations | ✅ SQL migrations | ⚠️ Manuel |
| Full-text search | ✅ Natif | ❌ Nécessite extension |
| Relations | ✅ Foreign keys | ⚠️ Dénormalisation |
🔐 Authentication : Comparable mais Différent
Supabase Auth
// Email/Password signup
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'secure_password',
options: {
data: {
full_name: 'John Doe',
age: 30
}
}
});
// OAuth providers (12+ supportés)
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: 'https://yourapp.com/callback'
}
});
// Magic link (passwordless)
const { data, error } = await supabase.auth.signInWithOtp({
email: 'user@example.com',
options: {
emailRedirectTo: 'https://yourapp.com/verify'
}
});
// Session management
const { data: { session } } = await supabase.auth.getSession();
const user = session?.user;
// Row Level Security (RLS) intégré
// SQL:
// CREATE POLICY "Users can only see their own data"
// ON public.users
// FOR SELECT
// USING (auth.uid() = id);
Firebase Auth
// Email/Password signup
import { getAuth, createUserWithEmailAndPassword, updateProfile } from 'firebase/auth';
const auth = getAuth();
const userCredential = await createUserWithEmailAndPassword(
auth,
'user@example.com',
'secure_password'
);
await updateProfile(userCredential.user, {
displayName: 'John Doe'
});
// OAuth providers (30+ supportés)
import { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
const provider = new GoogleAuthProvider();
const result = await signInWithPopup(auth, provider);
const user = result.user;
// Email link (passwordless)
import { sendSignInLinkToEmail } from 'firebase/auth';
await sendSignInLinkToEmail(auth, 'user@example.com', {
url: 'https://yourapp.com/verify',
handleCodeInApp: true
});
// Session management
import { onAuthStateChanged } from 'firebase/auth';
onAuthStateChanged(auth, (user) => {
if (user) {
console.log('User logged in:', user.uid);
}
});
Comparaison Auth
| Feature | Supabase | Firebase |
|---|---|---|
| Email/Password | ✅ | ✅ |
| OAuth providers | 12+ | 30+ |
| Phone auth | ✅ (Twilio) | ✅ |
| Magic links | ✅ | ✅ |
| Anonymous auth | ✅ | ✅ |
| MFA | ✅ (2025) | ✅ |
| Custom claims | ✅ (RLS policies) | ✅ (ID tokens) |
| Pricing | Inclus gratuit | Inclus gratuit |
⚡ Real-time : Approches Différentes
Supabase Real-time
// Supabase: PostgreSQL real-time via WebSocket
const channel = supabase
.channel('public:posts')
.on(
'postgres_changes',
{
event: 'INSERT',
schema: 'public',
table: 'posts'
},
(payload) => {
console.log('New post:', payload.new);
}
)
.on(
'postgres_changes',
{
event: 'UPDATE',
schema: 'public',
table: 'posts',
filter: 'author_id=eq.123'
},
(payload) => {
console.log('Post updated:', payload.new);
}
)
.subscribe();
// Presence (qui est en ligne)
const presence = supabase.channel('room:1');
presence
.on('presence', { event: 'sync' }, () => {
const state = presence.presenceState();
console.log('Online users:', Object.keys(state));
})
.on('presence', { event: 'join' }, ({ key, newPresences }) => {
console.log('User joined:', key);
})
.subscribe(async (status) => {
if (status === 'SUBSCRIBED') {
await presence.track({ user: 'Alice', online_at: new Date().toISOString() });
}
});
Firebase Real-time
// Firebase: Firestore real-time listeners
import { onSnapshot } from 'firebase/firestore';
// Écouter les changements d'un document
const unsubscribe = onSnapshot(
doc(db, 'posts', 'post123'),
(doc) => {
console.log('Document updated:', doc.data());
}
);
// Écouter une collection avec query
const q = query(collection(db, 'posts'), where('authorId', '==', '123'));
const unsubscribe = onSnapshot(q, (snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === 'added') {
console.log('New post:', change.doc.data());
}
if (change.type === 'modified') {
console.log('Modified post:', change.doc.data());
}
if (change.type === 'removed') {
console.log('Removed post:', change.doc.data());
}
});
});
// Realtime Database (legacy, plus rapide pour certains cas)
import { getDatabase, ref, onValue } from 'firebase/database';
const rtdb = getDatabase();
const presenceRef = ref(rtdb, 'presence/user123');
onValue(presenceRef, (snapshot) => {
const data = snapshot.val();
console.log('User status:', data);
});
🔧 Edge Functions vs Cloud Functions
Supabase Edge Functions (Deno)
// Supabase: Edge Functions avec Deno
// supabase/functions/hello/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
serve(async (req) => {
// Accès à Supabase depuis la fonction
const supabase = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
Deno.env.get('SUPABASE_ANON_KEY') ?? ''
);
// Parse request
const { name } = await req.json();
// Query database
const { data, error } = await supabase
.from('users')
.select('*')
.eq('name', name)
.single();
// Return response
return new Response(JSON.stringify({ user: data }), {
headers: { 'Content-Type': 'application/json' }
});
});
// Deploy: supabase functions deploy hello
// Performance: cold start ~50-100ms
Firebase Cloud Functions
// Firebase: Cloud Functions avec Node.js
import { onRequest } from 'firebase-functions/v2/https';
import { initializeApp } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
initializeApp();
export const hello = onRequest(async (request, response) => {
const db = getFirestore();
// Parse request
const { name } = request.body;
// Query Firestore
const snapshot = await db
.collection('users')
.where('name', '==', name)
.limit(1)
.get();
const user = snapshot.docs[0]?.data();
// Return response
response.json({ user });
});
// Deploy: firebase deploy --only functions
// Performance: cold start ~1-3 secondes (Node.js)
Comparaison Functions
| Critère | Supabase Edge | Firebase Cloud |
|---|---|---|
| Runtime | Deno | Node.js |
| Cold start | 50-100ms | 1-3s |
| Localisation | Edge (mondial) | Regions (limitées) |
| Pricing | Inclus 500K/mois | Complexe (CPU/mémoire) |
| TypeScript | Natif | Via compilation |
| Triggers DB | PostgreSQL | Firestore |
💰 Pricing : Transparence vs Complexité
Supabase Pricing (2025)
**Free Tier**:
- 500 MB database
- 1 GB file storage
- 2 GB bandwidth
- 500K Edge Function invocations
- Paused après 7 jours inactivité
**Pro ($25/mois)**:
- 8 GB database
- 100 GB storage
- 250 GB bandwidth
- 2M Edge Function invocations
- Daily backups
**Team ($599/mois)**:
- Ressources plus larges
- Priority support
- SOC2 compliance
**Enterprise**: Custom pricing
Firebase Pricing (2025)
**Spark (Free)**:
- 1 GB stored
- 10 GB/month bandwidth
- 50K document reads/day
- 20K document writes/day
- 125K Cloud Functions invocations/mois
**Blaze (Pay as you go)**:
- Firestore: $0.06 / 100K reads, $0.18 / 100K writes
- Storage: $0.026/GB
- Bandwidth: $0.12/GB
- Functions: $0.40 / million invocations + compute time
- Peut devenir cher rapidement !
**Exemple coût moyen**:
100K users actifs/mois: $200-500/mois
1M users: $2000-5000/mois
Comparaison coût (app moyenne)
| Ressource | Supabase Pro | Firebase Blaze |
|---|---|---|
| 100M reads | Inclus | $60 |
| 10M writes | Inclus | $18 |
| 50GB storage | Inclus | $1.30 |
| 100GB bandwidth | Inclus | $12 |
| 5M functions | Inclus (2M) + $30 | $150+ |
| Total | $55/mois | $240+/mois |
🎯 Cas d'Usage Recommandés
Choisir Supabase si :
// Application avec données relationnelles complexes
// E-commerce, SaaS, CRM
// Schema PostgreSQL
CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT NOT NULL,
price DECIMAL(10,2),
stock INT
);
CREATE TABLE orders (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE order_items (
id UUID PRIMARY KEY,
order_id UUID REFERENCES orders(id),
product_id UUID REFERENCES products(id),
quantity INT,
unit_price DECIMAL(10,2)
);
// Queries SQL puissantes
SELECT
u.name,
COUNT(o.id) AS order_count,
SUM(oi.quantity * oi.unit_price) AS total_spent
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
LEFT JOIN order_items oi ON o.id = oi.order_id
GROUP BY u.id, u.name
ORDER BY total_spent DESC
LIMIT 10;
Choisir Firebase si :
// Application avec données hiérarchiques/documents
// Chat app, social media, real-time collaboration
// Structure Firestore
users/{userId}/
profile: {...}
chats/{chatId}/
messages/{messageId}: {
text: "Hello",
timestamp: Timestamp,
authorId: "user123"
}
// Real-time updates simples
onSnapshot(doc(db, 'chats', chatId), (snapshot) => {
updateUI(snapshot.data());
});
🔮 Conclusion
Supabase : idéal pour applications nécessitant SQL, relations complexes, et pricing prévisible. Parfait pour SaaS, e-commerce, CRM.
Firebase : excellent pour prototypage rapide, apps temps réel, et intégration Google Cloud. Idéal pour chat, collaboration, mobile-first.
Recommandation 2025 :
- Nouveau projet SQL → Supabase
- Prototype rapide → Firebase
- Mobile app → Firebase (SDKs matures)
- SaaS B2B → Supabase (RLS, pricing)
- Budget limité → Supabase (plus prévisible)
Les deux plateformes sont excellentes. Le choix dépend de votre modèle de données et cas d'usage spécifiques.
Articles connexes
Pour approfondir le sujet, consultez également ces articles :




