Retour au blog
Next.jsSupabaseStack

Next.js + Supabase : le stack parfait pour les freelances

Pourquoi cette combinaison est idéale pour livrer vite et bien. Auth, RLS, Realtime, deploys Vercel — tout ce qu'il faut sans la complexité.

Antoine Verdure

Antoine Verdure

12 avril 202610 min de lecture

Après avoir construit 5 projets en production avec Next.js + Supabase — dont un SaaS de 480K lignes et un site vitrine avec formulaires et analytics — je suis convaincu que ce stack est le meilleur choix pour un freelance qui veut livrer vite sans sacrifier la qualité.

Cet article est le guide pratique que j'aurais voulu avoir en commençant. Pas de théorie — des patterns testés en production, avec les pièges que j'ai rencontrés et comment les éviter.

Pourquoi ce stack ?

En freelance, le temps c'est de l'argent. Littéralement. Chaque heure passée à configurer de l'infra, c'est une heure non facturée. Next.js + Supabase + Vercel, c'est :

  • Zéro config serveur — Vercel gère le déploiement, Supabase gère la base
  • Auth en 15 minutes — JWT, sessions, cookies, tout est intégré
  • Realtime gratuit — subscriptions Postgres sans WebSocket à configurer
  • Type safety bout en bout — du schéma Postgres aux composants React
  • Free tier généreux — tu ne paies que quand le projet génère du revenu

Le piège numéro 1 : les clients Supabase

C'est le truc qui fait perdre des heures à tout le monde. Supabase avec Next.js, c'est pas un client — c'est trois clients différents, et utiliser le mauvais casse tout silencieusement.

Client Service (API Routes uniquement) :

import { createServiceClient } from '@/lib/supabase/server'
const supabase = createServiceClient()
// Utilise service_role → bypass RLS

Client Serveur (Server Components) :

import { createClient } from '@/lib/supabase/server'
const supabase = await createClient()
// Utilise anon + cookies → respecte RLS

Client Navigateur (Client Components) :

import { createClient } from '@/lib/supabase/client'
const supabase = createClient()
// Utilise anon → respecte RLS

L'arbre de décision est simple :

  • Tu es dans une API Route ? → createServiceClient()
  • Tu es dans un Server Component ? → createClient() depuis server.ts
  • Tu es dans un Client Component ? → createClient() depuis client.ts

Le piège classique : tu crées un formulaire de contact public. L'utilisateur n'est pas authentifié. Tu utilises le client anon dans ton API Route. Boom : "new row violates row-level security policy". Parce que l'anon key respecte RLS, et ta policy n'autorise pas l'insert anonyme — ou pire, tu n'as pas de policy du tout.

La solution : utilise createServiceClient() dans les API Routes publiques. Il bypass RLS avec la service_role key. Et ne jamais exposer cette clé côté client.

RLS : la sécurité qui mord

Row Level Security, c'est génial. Mais ça mord les débutants. Voici les patterns qui fonctionnent :

Pour les formulaires publics (contact, newsletter) :

-- Autoriser l'insertion anonyme
CREATE POLICY "allow_anon_insert" ON contacts
  FOR INSERT TO anon WITH CHECK (true);
-- Pas de SELECT pour anon = personne ne peut lire

Pour les données utilisateur :

-- Chaque user voit uniquement ses données
CREATE POLICY "user_own_data" ON todos
  FOR ALL TO authenticated
  USING (auth.uid() = user_id);

Règle d'or : RLS est activé par défaut sur toutes tes tables. Si tu oublies de créer une policy, rien ne passe. C'est sécurisé par défaut, mais ça peut être frustrant quand tu débogues un formulaire qui "ne marche pas" alors que le code est correct.

Le pattern API Route qui marche

Après plusieurs itérations, voici le pattern que j'utilise dans tous mes projets :

  1. Rate limiting — 5 requêtes / 15 minutes par IP (en mémoire, suffisant pour un MVP)
  2. Validation Zod — un schéma par endpoint, parse avant tout
  3. Insert Supabase — avec createServiceClient()
  4. Analytics — tracking PostHog server-side
  5. Réponse JSON — toujours un { success: true/false }

Ce pipeline en 5 étapes est répliqué sur chaque endpoint. C'est répétitif ? Oui. Mais c'est aussi prévisible, testable, et debuggable. En freelance, la prévisibilité vaut plus que l'élégance.

Type safety de bout en bout

Un des plus gros avantages du combo Next.js + Supabase : le typage ne s'arrête pas à React.

Le workflow :

  1. Tu modifies le schéma dans une migration SQL
  2. Tu lances npm run supabase:types
  3. TypeScript te dit immédiatement tous les endroits du code affectés

Plus de "j'ai renommé une colonne et je le découvre en production". Le compilateur attrape tout. Combiné avec des schémas Zod pour la validation runtime, tu as une double couche de sécurité sur les types.

Déploiement : le workflow en 3 commandes

C'est là que le stack brille vraiment. Déployer en production :

  1. supabase db push — applique les migrations sur la base distante
  2. git push — Vercel détecte, build, déploie automatiquement
  3. npm run test:e2e:prod — smoke tests contre la prod

Pas de Docker à configurer. Pas de serveur à maintenir. Pas de CI/CD complexe à écrire. Tu push, c'est en prod. Le free tier Vercel + le free tier Supabase couvrent la majorité des projets freelance sans sortir la carte bleue.

Les gotchas en production

Quelques pièges que j'ai rencontrés sur mes projets en production :

  • PostHog region mismatch — clé API EU pointant vers l'endpoint US. Résultat : 404 sur config.js, 401 sur les feature flags. Solution : vérifier que NEXT_PUBLIC_POSTHOG_HOST correspond à la région de ta clé.
  • Rate limiting en mémoire — ça marche bien pour un MVP, mais ça se réinitialise à chaque redeploy Vercel (serverless = stateless). Pour la production sérieuse, passe à Upstash Redis.
  • Variables d'environnement — seules les variables préfixées NEXT_PUBLIC_sont exposées au navigateur. Oublie le préfixe sur ta Supabase URL = formulaire cassé sans erreur visible côté serveur.
  • Server Components par défaut — Next.js 15 rend tout en Server Component. Ajoute 'use client' uniquement si tu as besoin de hooks, d'event handlers ou d'état. Moins de client JS = meilleures perfs = meilleur Core Web Vitals.

Mon conseil pour les freelances

Si tu débutes en freelance et que tu cherches un stack, arrête de comparer. Prends Next.js + Supabase + Vercel, livre ton premier projet, et itère. Le meilleur stack, c'est celui avec lequel tu livres — pas celui qui a le plus d'étoiles sur GitHub.

Les patterns décrits dans cet article — trois clients Supabase, RLS par défaut, validation Zod, API Routes en pipeline, types auto-générés — couvrent 90% des besoins freelance. Le reste, tu l'apprendras en livrant.

Et quand tu tomberas sur le message "new row violates row-level security policy", tu sauras exactement quoi faire.

Antoine Verdure

Un projet en tête ?

Cet article t'a donné des idées ? Discutons de comment les mettre en œuvre dans ton contexte. 30 minutes, sans engagement.

Me contacter