Vizion Web
Backend, Data & Infra

ORM

Définition

Object-Relational Mapping. Bibliothèque qui permet d'interagir avec la base de données via des objets typés plutôt qu'en SQL brut. Exemples : Drizzle, Prisma.

Comment ça marche

Un ORM (Object-Relational Mapper) fait le pont entre votre code applicatif et la base de données. Vous déclarez votre schéma dans le langage de l'application (TypeScript, Python, Go), et l'ORM génère les requêtes SQL correspondantes. Vous écrivez db.users.findMany({ where: { active: true } }) au lieu de SELECT * FROM users WHERE active = true. L'ORM s'occupe du mapping entre lignes SQL et objets, de la gestion du pool de connexions, parfois des migrations de schéma. Les ORM modernes (Drizzle, Prisma, SQLAlchemy) génèrent du SQL propre et performant, sans la magie obscure des ORM d'il y a 10 ans.

À quoi ça sert

L'ORM apporte trois bénéfices concrets. La sécurité de type : le compilateur sait que users.email est une string et bloque les fautes de frappe au build, pas en production. La productivité : l'autocomplétion fait apparaître tous les champs et relations, ce qui accélère le développement et limite la lecture de schémas. La maintenabilité : quand on renomme une colonne, le compilateur signale tous les endroits à mettre à jour. Sur un projet à plusieurs développeurs ou qui dure plus de quelques mois, c'est un investissement qui se rentabilise vite.

Drizzle vs Prisma

Drizzle est l'ORM TypeScript moderne, minimaliste, qui colle au plus près de SQL : on écrit une requête comme on l'écrirait en SQL, avec tous les avantages du typage. Pas de runtime lourd, bundle minuscule, parfait pour le edge runtime. Prisma reste très utilisé, plus ancien, avec une syntaxe ORM classique et un écosystème mature (Prisma Studio, migrations bien rodées). Son défaut : un runtime plus lourd, des cold starts plus longs en serverless, et une syntaxe parfois éloignée de SQL. Sur les nouveaux projets Next.js, on tend à choisir Drizzle. Sur un projet existant en Prisma, pas de raison de migrer juste pour le principe.

Quand ne pas l'utiliser

Pour des requêtes très complexes (analytics avec fenêtrage, CTE récursives, pivots, agrégations multi-tables) un ORM peut devenir un frein : il faut bricoler avec ses helpers ou tomber dans le mode "SQL brut". Dans ces cas, on écrit directement la requête en SQL paramétré et on la mappe à la main. Pour les scripts ponctuels (migrations one-shot, exports) un client SQL léger suffit largement. Pour les bases NoSQL (MongoDB, DynamoDB), les ORM existent mais l'intérêt est moindre puisque le typage et le mapping sont déjà natifs. La règle : ORM pour le code applicatif récurrent, SQL pur pour le sur-mesure.

Les migrations

L'ORM ne se résume pas aux requêtes : il gère aussi les migrations de schéma. À chaque changement (ajout de colonne, nouvelle table, index), on génère un fichier de migration versionné en Git, qu'on applique en production de façon contrôlée. Drizzle Kit, Prisma Migrate, Alembic font ce travail. C'est ce qui permet à plusieurs développeurs de modifier le schéma sans conflit, et de garder un historique propre des évolutions. Sur une grosse table, certaines migrations bloquent la production : on les fait alors en plusieurs étapes (ajouter colonne nullable, backfill asynchrone, ajouter contrainte) pour éviter de geler les écritures.

Les pièges à éviter

Le piège classique du N+1 : on boucle sur une liste et chaque itération déclenche une requête. Avec 100 utilisateurs, ça fait 101 requêtes au lieu d'une. On le détecte en regardant les logs SQL en développement et on le corrige avec des joins ou du eager loading. Autre piège : charger tous les champs d'une table quand seuls deux sont utilisés. Les ORM modernes proposent des selects partiels (Drizzle .select() précis, Prisma select: {}), on les utilise dès qu'on a une table large. Enfin, on ne fait jamais confiance à l'ORM pour la sécurité : la RLS de PostgreSQL ou les permissions au niveau API restent indispensables.

Les bonnes pratiques

On commit le schéma et les migrations dans Git, comme du code. On lance les migrations en CI, pas à la main en production. On évite d'exposer directement les objets ORM côté frontend (DTO et schémas Zod entre la base et l'API). On utilise les transactions explicites pour les opérations multi-tables qui doivent être atomiques (création de commande + lignes de commande + paiement). On profile les requêtes lentes en regardant le SQL généré, et on n'hésite pas à passer en SQL brut sur les 10% de cas où l'ORM est en travers du chemin. Le code reste lisible, et la base reste rapide.

Autres termes de la catégorie Backend, Data & Infra