À quoi ça sert

Pour la plupart des applis (web ou mobile), tu as toujours besoin des mêmes briques :

  1. Une base de données pour stocker tes objets métier.
  2. Un système d'authentification (signup, login, mot de passe oublié, OAuth Google/GitHub).
  3. Une API qui expose la base à ton front.
  4. Un endroit pour stocker les fichiers (avatars, PDFs, images).
  5. 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 vs Firebase

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.

En une phrase

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 recettes et likes à la souris (ou en SQL) dans l'interface.
  • Tu actives email + password dans la section Auth.
  • Tu crées un bucket photos dans la section Storage.
  • Tu installes supabase dans 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).
⚠ Ne JAMAIS exposer la clé 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 graphiqueTable Editor → New table. Tu nommes la table, tu ajoutes les colonnes, tu valides.
  • SQL Editor — pour ceux qui préfèrent le SQL :
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

bash (Python)
uv add supabase
bash (JavaScript)
npm install @supabase/supabase-js

4. Initialiser le client

Les deux SDK suivent la même logique : URL + clé anon → client.

python
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)
javascript
import { createClient } from '@supabase/supabase-js'

const supabase = createClient(
    process.env.SUPABASE_URL,
    process.env.SUPABASE_ANON_KEY
)
Variables d'environnement

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.

python
# 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()
javascript
// 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 :

python
# 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()
javascript
// 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.

⚠ Activer RLS sur toutes les tables exposées au client

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) :

sql
-- 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.

python
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.

javascript
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.

javascript
const { data, error } = await supabase.functions.invoke('envoyer-email', {
    body: { destinataire: 'alice@example.com', sujet: 'Bienvenue' }
})

Aide-mémoire

python — opérations courantes
# 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
opérateurs PostgREST courants
.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 Supabasenpx supabase ou brew 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).
  • Documentationsupabase.com/docs est 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.