Supabase
Un backend complet prêt à l'emploi : base PostgreSQL, authentification, stockage de fichiers, API REST automatique, temps réel. Tu crées un projet, tu récupères deux clés, et tu écris ton appli — pas de serveur à monter, pas d'auth à coder.
À quoi ça sert
Pour la plupart des applis (web ou mobile), tu as toujours besoin des mêmes briques :
- Une base de données pour stocker tes objets métier.
- Un système d'authentification (signup, login, mot de passe oublié, OAuth Google/GitHub).
- Une API qui expose la base à ton front.
- Un endroit pour stocker les fichiers (avatars, PDFs, images).
- Parfois, des notifications en temps réel quand des données changent.
Sans Supabase, tu codes tout ça toi-même : Postgres dans Docker, bcrypt + JWT pour l'auth, FastAPI pour les endpoints CRUD, un bucket S3 ou MinIO pour les fichiers, des websockets si tu veux du temps réel. Une semaine de plomberie avant d'écrire la première ligne de logique métier.
Avec Supabase, ces 5 briques sont installées et configurées dès la création du projet. Tu commences directement par ton métier.
- PostgreSQL géré — une vraie base relationnelle (pas un store NoSQL). Tu écris du SQL standard, tu peux y brancher n'importe quel client Postgres.
- API REST & GraphQL automatiques — chaque table crée immédiatement ses endpoints CRUD via PostgREST, sans coder.
- Auth intégrée — signup/login email+mot de passe, magic link, OAuth (Google, GitHub, etc.) en quelques lignes.
- Storage — buckets de fichiers avec permissions adossées à l'auth.
- Realtime — abonnements aux changements d'une table via websocket, sans serveur dédié.
- Edge Functions — fonctions serverless en Deno (TypeScript) pour la logique custom.
- Open source — tu peux héberger toi-même la stack complète si tu veux sortir du cloud Supabase.
Supabase se présente comme « l'alternative open-source à Firebase ». Différence clé : Firebase utilise Firestore (NoSQL, propriétaire, lock-in Google), Supabase utilise PostgreSQL (relationnel, standard, portable n'importe où). Si tu connais déjà du SQL, l'apprentissage est quasi-gratuit. Si tu veux migrer un jour, tu pars avec un dump Postgres standard.
Supabase, c'est Postgres + tout ce qu'on met autour habituellement, installé en 2 minutes dans le cloud, et utilisable depuis n'importe quel langage via SDK ou directement via l'API REST.
Un exemple d'usage
Tu prépares ton projet de fin de formation : une appli de partage de recettes. Les fonctionnalités prévues :
- Inscription / connexion des utilisateurs.
- Chacun publie ses recettes (titre, ingrédients, photo).
- On peut liker les recettes des autres.
- Le compteur de likes se met à jour en direct (sans recharger).
Sans Supabase, l'arborescence à monter ressemblerait à :
- Backend FastAPI avec endpoints
/auth,/recettes,/likes. - Postgres dans Docker pour la BD, Alembic pour les migrations.
- Hash bcrypt + JWT pour l'auth, gestion du refresh token.
- S3/MinIO pour les photos.
- WebSocket dédié pour le compteur en temps réel.
- Hébergement de tout ça quelque part.
Avec Supabase :
- Tu crées un projet sur supabase.com.
- Tu crées les tables
recettesetlikesà la souris (ou en SQL) dans l'interface. - Tu actives email + password dans la section Auth.
- Tu crées un bucket
photosdans la section Storage. - Tu installes
supabasedans ton projet front (ou Python), tu colles les deux clés, tu codes la logique.
Le temps gagné, c'est tout ce qui n'est pas spécifique à ton appli. Pour un MVP, un prototype, un projet pédagogique, ou même un SaaS modeste qui démarre, c'est massif.
How-to : démarrer avec Supabase
1. Créer un projet
- Va sur
supabase.com, crée un compte (GitHub recommandé). - Clique New project. Choisis un nom, un mot de passe pour la BD Postgres (à garder précieusement), et une région proche de toi (Paris pour l'UE).
- Le projet se provisionne en ~2 minutes.
Une fois le projet prêt, va dans Project Settings → API. Note deux valeurs :
- Project URL :
https://xxxx.supabase.co - anon public key : un long JWT — c'est la clé publique, elle peut vivre côté client (front).
service_role
Sur la même page, tu verras une clé service_role. Elle
bypasse toutes les règles de sécurité. Elle ne doit
jamais apparaître dans du code client (front,
mobile, repo public). Elle reste sur ton serveur, dans une variable
d'environnement. Si elle fuite, considère qu'on a accès en
écriture/lecture à toute ta base.
2. Créer une table
Deux chemins, équivalents :
- Interface graphique — Table Editor → New table. Tu nommes la table, tu ajoutes les colonnes, tu valides.
- SQL Editor — pour ceux qui préfèrent le SQL :
CREATE TABLE recettes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES auth.users(id),
titre TEXT NOT NULL,
ingredients TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
Note la référence à auth.users(id) : Supabase fournit déjà
le schéma auth avec sa propre table d'utilisateurs.
On l'utilise comme clé étrangère.
3. Installer le SDK
uv add supabase
npm install @supabase/supabase-js
4. Initialiser le client
Les deux SDK suivent la même logique : URL + clé anon → client.
import os
from supabase import create_client, Client
url: str = os.environ["SUPABASE_URL"]
key: str = os.environ["SUPABASE_ANON_KEY"]
supabase: Client = create_client(url, key)
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_ANON_KEY
)
Stocke SUPABASE_URL et SUPABASE_ANON_KEY
dans un fichier .env (jamais commité — ajoute-le à
.gitignore). En Python, charge-le avec
python-dotenv. Dans Next.js/Vite, le préfixe
NEXT_PUBLIC_ ou VITE_ est requis pour
que la clé soit accessible côté client.
5. CRUD sur une table
Le SDK propose une API fluide qui appelle l'API REST de Supabase (PostgREST) par-dessus.
# INSERT
supabase.table("recettes").insert({
"titre": "Tarte tatin",
"ingredients": "pommes, beurre, sucre, pâte",
}).execute()
# SELECT avec filtre
res = (
supabase.table("recettes")
.select("id, titre, created_at")
.eq("user_id", current_user_id)
.order("created_at", desc=True)
.limit(10)
.execute()
)
for row in res.data:
print(row["titre"])
# UPDATE / DELETE
supabase.table("recettes").update({"titre": "Tarte Tatin"}).eq("id", recette_id).execute()
supabase.table("recettes").delete().eq("id", recette_id).execute()
// INSERT
await supabase.from('recettes').insert({
titre: 'Tarte tatin',
ingredients: 'pommes, beurre, sucre, pâte',
})
// SELECT avec filtre
const { data, error } = await supabase
.from('recettes')
.select('id, titre, created_at')
.eq('user_id', currentUserId)
.order('created_at', { ascending: false })
.limit(10)
// UPDATE / DELETE
await supabase.from('recettes').update({ titre: 'Tarte Tatin' }).eq('id', recetteId)
await supabase.from('recettes').delete().eq('id', recetteId)
Sous le capot : chaque appel devient une requête HTTP
GET /rest/v1/recettes?...,
POST /rest/v1/recettes, etc. Tu peux aussi appeler l'API
REST directement avec fetch ou requests, sans
SDK. Le SDK est juste un wrapper ergonomique.
6. Authentification
Active Email dans Authentication → Providers (déjà actif par défaut). Le code client :
# Inscription
supabase.auth.sign_up({"email": "alice@example.com", "password": "un_mdp_solide"})
# Connexion
res = supabase.auth.sign_in_with_password({
"email": "alice@example.com",
"password": "un_mdp_solide",
})
print(res.user.id) # UUID de l'utilisateur
print(res.session.access_token) # JWT à utiliser pour les requêtes suivantes
# Déconnexion
supabase.auth.sign_out()
// Inscription
await supabase.auth.signUp({ email: 'alice@example.com', password: 'un_mdp_solide' })
// Connexion
const { data, error } = await supabase.auth.signInWithPassword({
email: 'alice@example.com',
password: 'un_mdp_solide',
})
// Récupérer l'utilisateur courant
const { data: { user } } = await supabase.auth.getUser()
// Déconnexion
await supabase.auth.signOut()
Une fois connecté, le SDK garde le JWT et l'envoie automatiquement
dans l'en-tête Authorization: Bearer ... de chaque requête
suivante. Côté Postgres, ce JWT est interprété et alimente les règles
RLS (cf. plus bas).
Pour activer la connexion via Google/GitHub : Authentication →
Providers, tu actives le provider, tu colles le client ID/secret
(récupérés sur la console du provider). Une seule ligne change côté
client : signInWithOAuth({ provider: 'google' }).
7. Row Level Security (RLS) — incontournable
Par défaut, dès que tu actives RLS sur une table, plus aucun accès n'est possible depuis la clé anon. Tu dois écrire des policies qui décrivent qui peut faire quoi. C'est le mécanisme de sécurité central de Supabase.
Sans RLS, n'importe qui ayant la clé anon (= n'importe quel visiteur de ton appli web) peut lire et modifier toutes tes tables. RLS n'est pas optionnel pour une appli en production.
Exemple : « un utilisateur ne peut voir que ses propres recettes ». On active RLS et on écrit deux policies (lecture, écriture) :
-- Activer RLS sur la table
ALTER TABLE recettes ENABLE ROW LEVEL SECURITY;
-- Policy 1 : un user peut SELECT ses propres recettes
CREATE POLICY "recettes_select_own"
ON recettes FOR SELECT
USING (auth.uid() = user_id);
-- Policy 2 : un user peut INSERT en se mettant comme propriétaire
CREATE POLICY "recettes_insert_self"
ON recettes FOR INSERT
WITH CHECK (auth.uid() = user_id);
auth.uid() est une fonction Postgres fournie par Supabase
qui renvoie l'UUID de l'utilisateur connecté (extrait du JWT). Si la
requête vient d'un visiteur non connecté, elle renvoie
NULL et la policy bloque tout.
Mentale model utile : RLS s'applique au niveau Postgres, pas au niveau du SDK. Même si quelqu'un appelle l'API REST en bypassant ton code, la policy s'applique. C'est ce qui rend l'architecture « clé anon côté client » sûre.
Les autres services en bref
Storage
Buckets de fichiers (images, PDFs, etc.). Chaque bucket peut être public ou privé, et les accès sont régis par des policies RLS, comme pour les tables.
with open("avatar.png", "rb") as f:
supabase.storage.from_("avatars").upload("alice/avatar.png", f)
url = supabase.storage.from_("avatars").get_public_url("alice/avatar.png")
Realtime
Abonnements aux changements d'une table via WebSocket. Utile pour les feeds, chats, dashboards live.
supabase
.channel('recettes-changes')
.on('postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'recettes' },
(payload) => console.log('Nouvelle recette :', payload.new)
)
.subscribe()
Edge Functions
Pour la logique custom qui ne peut pas vivre côté client (envoyer un email avec une clé secrète, appeler une API tierce avec un token privé, etc.) : des fonctions serverless en Deno (TypeScript), déployées via la CLI Supabase. Tu les appelles depuis ton client comme une fonction RPC.
const { data, error } = await supabase.functions.invoke('envoyer-email', {
body: { destinataire: 'alice@example.com', sujet: 'Bienvenue' }
})
Aide-mémoire
# SELECT avec plusieurs filtres
supabase.table("t").select("*").eq("col", val).gt("n", 5).execute()
# Jointure (relation déclarée par foreign key)
supabase.table("recettes").select("*, profils(nom)").execute()
# Pagination
supabase.table("t").select("*").range(0, 9).execute() # 10 premiers
# Upsert (INSERT ou UPDATE selon clé primaire)
supabase.table("t").upsert({"id": 1, "x": "y"}).execute()
# Récupérer l'utilisateur connecté
user = supabase.auth.get_user().user
.eq(col, val) # col = val
.neq(col, val) # col != val
.gt(col, val) # col > val
.gte(col, val) # col >= val
.lt / .lte # < et <=
.in_(col, [a, b, c]) # col IN (...)
.like(col, '%foo%') # LIKE
.is_(col, None) # col IS NULL
.order(col, desc=True)
.limit(n)
.range(start, end)
Supabase et le reste de l'écosystème
- SQLite — pour le dev local hors-ligne ou un prototype mono-utilisateur, SQLite reste plus simple. Supabase prend le relais dès que tu as besoin d'auth, multi-utilisateurs ou d'un déploiement en ligne.
- SQLAlchemy — Supabase est du Postgres. Tu peux y connecter SQLAlchemy avec la chaîne de connexion fournie dans Project Settings → Database, et utiliser l'ORM en parallèle du SDK Supabase pour la logique côté serveur.
- FastAPI — pattern hybride courant : tu utilises Supabase pour l'auth + la BD, et FastAPI pour la logique métier qui ne tient pas dans des Edge Functions (calculs lourds, ML, intégrations tierces complexes). Le client front parle aux deux.
- Docker — Supabase peut être auto-hébergé via
Docker Compose (image officielle
supabase/supabase). Utile si tu refuses le cloud, ou pour un dev local fidèle à la prod.
Pour aller plus loin
- CLI Supabase —
npx supabaseoubrew install supabase/tap/supabase. Permet de gérer les migrations SQL versionnées dans Git, de générer les types TypeScript depuis ton schéma, et de lancer une instance Supabase complète en local pour le dev. - Quotas du plan gratuit — 500 Mo de BD, 1 Go de Storage, 50 000 utilisateurs actifs/mois, projet en pause après 7 jours d'inactivité. Largement suffisant pour un projet pédagogique ou un MVP.
- Vrai prod — pense à activer les backups quotidiens (plan payant), à configurer le rate limiting de l'auth, et à passer en revue toutes tes policies RLS (chaque table doit en avoir).
- Documentation —
supabase.com/docsest bien fait et progresse vite. La référence du SDK Python est moins complète que celle du SDK JS — quand un détail manque côté Python, regarde la doc JS, l'API est calquée.