← Retour aux articles
Backend SupabasePostgresAuth

Supabase : le backend propulsé par Postgres pour les applications modernes

· 6 min de lecture

Tout projet nécessitant une base de données, de l’authentification, du stockage de fichiers et des mises à jour en temps réel impliquait autrefois d’assembler cinq services différents et d’en maintenir la plomberie. Supabase condense tout cela dans une unique plateforme open source construite au-dessus de Postgres, offrant la rapidité d’un backend managé tout en gardant vos données dans une base SQL standard. Ce qui rend la solution intéressante n’est pas le confort, c’est le fait que tout se ramène à des primitives Postgres classiques : tables, policies, fonctions et triggers.

Postgres au cœur du système

Supabase fournit une véritable instance Postgres dès le premier jour, pas une abstraction propriétaire posée par-dessus. Vous disposez de SQL réel, de vraies clés étrangères, de vraies transactions, de vrais index et de vraies extensions comme pgvector ou postgis. Le SDK client propose un query builder fluide qui compile vers du SQL standard, ce qui permet de prototyper rapidement tout en gardant la possibilité d’écrire des requêtes brutes quand le schéma devient exigeant :

import { createClient } from '@supabase/supabase-js';

const supabase = createClient(url, anonKey);

const { data, error } = await supabase
  .from('posts')
  .select('id, title, author:profiles(name)')
  .eq('status', 'published')
  .order('created_at', { ascending: false })
  .limit(10);

La syntaxe imbriquée author:profiles(name) résout automatiquement la clé étrangère, ce qui supprime la majorité des requêtes de jointure que vous auriez sinon écrites à la main.

Authentification sans le boilerplate

L’authentification est généralement l’endroit où les side projects et les MVP perdent un temps considérable. Supabase Auth fournit email et mot de passe, magic links, OTP, téléphone et OAuth pour tous les grands fournisseurs, le tout adossé à des JWT que n’importe quel service connecté à Postgres peut vérifier. La session est stockée côté client, rafraîchie automatiquement et exposée via un listener unique :

const { data, error } = await supabase.auth.signInWithPassword({
  email,
  password,
});

supabase.auth.onAuthStateChange((_event, session) => {
  // Propager la session dans le state de l'application
});

L’utilisateur est stocké dans une table dédiée auth.users que vous pouvez référencer depuis votre propre schéma, ce qui rend la section suivante possible.

Row Level Security : l’autorisation au niveau base de données

Row Level Security est la fonctionnalité phare de Supabase, et aussi celle sur laquelle la plupart des débutants butent. Au lieu d’encoder les règles d’autorisation dans votre couche API, vous les écrivez comme des policies Postgres qui s’exécutent sur chaque requête. La base de données elle-même impose qui peut voir et modifier quoi, ce qui signifie qu’un client compromis ne peut pas contourner les règles :

alter table posts enable row level security;

create policy "Users can read published posts"
  on posts for select
  using (status = 'published' or auth.uid() = author_id);

create policy "Authors can update their own posts"
  on posts for update
  using (auth.uid() = author_id);

Écrire des routes API qui laissent fuiter des données devient bien plus difficile, car il faut explicitement contourner RLS avec la service role key. En pratique, la quasi-totalité des requêtes passe par l’anon key et la base se charge du reste.

Souscriptions realtime

Supabase expose les flux de changements Postgres via websockets, si bien que chaque insertion, mise à jour ou suppression peut être poussée au client instantanément. Combiné à RLS, chaque abonné ne reçoit que les lignes qu’il est autorisé à voir, ce qui rend les fonctionnalités realtime multi-tenants triviales à construire :

const channel = supabase
  .channel('messages')
  .on(
    'postgres_changes',
    { event: 'INSERT', schema: 'public', table: 'messages' },
    (payload) => {
      setMessages((prev) => [...prev, payload.new]);
    }
  )
  .subscribe();

Pas de polling, pas de serveur websocket custom, aucune infrastructure pub/sub à opérer. Chat, dashboards, édition collaborative et notifications live passent tous par la même primitive.

Stockage avec URLs signées

Le module Storage est un bucket compatible S3 sur lequel s’applique le même modèle RLS que sur les tables. Vous pouvez servir des assets publics directement, ou générer des URLs signées à durée de vie courte pour du contenu privé. L’upload et le download passent tous deux par le même SDK :

await supabase.storage
  .from('avatars')
  .upload(`${user.id}/avatar.png`, file, {
    cacheControl: '3600',
    upsert: true,
  });

const { data } = await supabase.storage
  .from('documents')
  .createSignedUrl(filePath, 60);

Les policies sur les objets de stockage fonctionnent exactement comme celles des tables, ce qui maintient un modèle mental cohérent sur toute la plateforme.

Edge Functions pour la logique custom

Quand il faut de la logique côté serveur qui n’a pas sa place dans la base, comme des webhooks de paiement, des appels à des API tierces ou des jobs planifiés, Supabase exécute des Edge Functions basées sur Deno, déployées globalement. Elles ont accès au même contexte d’authentification et peuvent être invoquées depuis le SDK client ou appelées en HTTP :

import { createClient } from 'jsr:@supabase/supabase-js';

Deno.serve(async (req) => {
  const { to, subject, body } = await req.json();

  const supabase = createClient(
    Deno.env.get('SUPABASE_URL')!,
    Deno.env.get('SUPABASE_ANON_KEY')!,
    { global: { headers: { Authorization: req.headers.get('Authorization')! } } }
  );

  // ... envoyer l'email

  return new Response(JSON.stringify({ ok: true }));
});

Les Edge Functions gardent les secrets côté serveur et évitent d’avoir à monter un backend Node séparé pour de simples intégrations.

Requêtes typées depuis le schéma

Supabase peut introspecter votre base de données et générer des types TypeScript qui alimentent directement le SDK client. Chaque requête devient type-safe sur la base de vos colonnes et relations réelles, et les migrations passant par SQL, les types reflètent toujours la vérité :

import type { Database } from '@/types/db';

const supabase = createClient<Database>(url, anonKey);

// data est automatiquement typé en Post[]
const { data } = await supabase.from('posts').select('*');

Branchée dans un job CI, la génération garantit que le front ne dérive jamais du schéma de la base, même quand plusieurs personnes poussent des migrations en parallèle.

Conclusion

Supabase est ce que l’on obtient quand Postgres rencontre l’ergonomie d’un backend as a service moderne. Vous conservez le SQL complet et la portabilité qui va avec, tout en déléguant la plomberie peu différenciante de l’auth, du stockage, du realtime et du déploiement. Pour la plupart des side projects, startups et outils internes, cela économise des semaines de setup et vous laisse un backend que vous pouvez encore comprendre, inspecter et migrer le jour où vous en aurez besoin.