Prisma vs TypeORM : retour d'expérience sur 8 projets NestJS

12/03/2026 · Mis à jour le 14/10/2026
On a utilisé TypeORM sur 7 projets NestJS et Prisma sur 1. Voici ce qu'on en retient : pas de la théorie, du vécu.
Le contexte
Quand on a commencé à construire des API NestJS en 2021, TypeORM était le choix par défaut. Intégration native avec NestJS, documentation correcte, communauté active. Puis Prisma est arrivé avec une approche radicalement différente : schema-first, type-safe par design, et une DX qui promettait de changer la donne.
On a basculé un projet sur Prisma pour voir. Voici ce qu'on a appris.
Définition des modèles : décorateurs vs schema
TypeORM définit les modèles avec des décorateurs TypeScript. C'est verbeux mais lisible :
@Entity()
export class Appointment extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
@ManyToOne(() => Workspace, (ws) => ws.appointments)
@JoinColumn()
workspace: Workspace;
@ManyToOne(() => Project, (p) => p.appointments)
@JoinColumn()
project: Project;
}
Prisma utilise un fichier .prisma dédié, plus concis :
model Relationship {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
sponsor User? @relation("Sponsor", fields: [sponsorId], references: [id])
downline User? @relation("Downline", fields: [downlineId], references: [id])
sponsorId String?
downlineId String?
status String @default("PENDING")
}
Notre tip : le schema Prisma est plus rapide à lire et à modifier. Mais les décorateurs TypeORM permettent de garder la logique ORM avec le code TypeScript, pas de fichier séparé à synchroniser mentalement.
Typage : là où Prisma écrase
Le client Prisma génère des types à partir du schema. Quand on écrit prisma.relationship.findMany(), l'autocomplétion connaît exactement les champs, les relations, et les filtres possibles. C'est du type-safety de bout en bout, sans effort.
Avec TypeORM, le typage existe mais il est plus lâche. Depuis la version 0.3, les relations d'un find() s'écrivent sous forme d'objet et sont vérifiées à la compilation (l'ancienne syntaxe en tableau de chaînes, qui ne l'était pas, a été retirée en 1.0). En revanche, le type renvoyé ne dit pas quelles relations ont été chargées : une relation non demandée vaut undefined à l'exécution alors que son type promet un objet.
Notre tip : sur un projet avec beaucoup de relations complexes (self-referencing, many-to-many), le typage Prisma évite des bugs qu'on ne découvrirait qu'en prod avec TypeORM.
Soft deletes : avantage TypeORM
TypeORM gère les soft deletes nativement avec @DeleteDateColumn() :
export class BaseEntity {
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
@DeleteDateColumn()
deletedAt?: Date;
}
Un softDelete() remplit le champ, et tous les find() excluent automatiquement les entités supprimées. Transparent.
Prisma n'a pas de soft delete natif. On ajoute un champ deletedAt DateTime? et on doit filtrer manuellement partout avec where: { deletedAt: null }. Sur un projet avec 15+ entités, c'est une source d'erreurs.
Notre tip : si le soft delete est central dans votre logique (audit trail, RGPD, corbeille), TypeORM simplifie la vie. Avec Prisma, prévoyez une extension Prisma Client ($extends, composant query) pour automatiser le filtrage : le middleware $use a été retiré en version 6.14. Elle ne couvre pas les relations chargées avec include, qu'il faut encore filtrer à la main.
Migrations : deux philosophies
TypeORM peut auto-synchroniser le schéma en dev (synchronize: true). Pratique mais dangereux, on l'a désactivé en prod dès le premier jour. Les migrations (écrites à la main ou générées depuis le diff des entités avec migration:generate) fonctionnent, mais on a accumulé 86 fichiers de migration sur un projet. Le tooling est correct sans plus.
Prisma a un workflow migration plus propre : prisma migrate dev crée une migration à partir du diff du schema. C'est plus prévisible et le fichier SQL généré est lisible. Par contre, une migration de données demande une étape de plus : prisma migrate dev --create-only génère le fichier SQL sans l'appliquer, on y ajoute ses requêtes, puis on l'applique, le tout en SQL et sans code applicatif.
Notre tip : Prisma gagne sur les migrations de schéma. TypeORM gagne quand on a besoin de migrations de données complexes.
Relations self-referencing : Prisma gagne
Sur le projet MLM (réseau de parrainage), on avait une relation self-referencing : un utilisateur sponsorise d'autres utilisateurs, qui sponsorisent d'autres utilisateurs. Avec Prisma, c'est déclaratif et clair grâce aux relations nommées (@relation("Sponsor"), @relation("Downline")).
Avec TypeORM, les self-referencing many-to-many nécessitent plus de configuration et le eager loading devient vite un piège de performance si on ne fait pas attention.
Performance : pas de différence notable
Sur nos volumes (quelques milliers à quelques dizaines de milliers de lignes), on n'a pas mesuré de différence significative. Les deux génèrent du SQL propre. Les problèmes de performance viennent toujours du même endroit : des N+1 queries qu'on n'a pas anticipées.
Notre verdict
| Critère | TypeORM | Prisma |
|---|---|---|
| DX / autocomplétion | Correct | Excellent |
| Soft deletes | Natif | Manuel |
| Migrations schema | Correct | Meilleur |
| Migrations data | Flexible | Limité |
| Self-referencing | Verbeux | Clair |
| Écosystème NestJS | Module officiel (@nestjs/typeorm) |
Service à écrire (recette officielle) |
| Courbe d'apprentissage | Progressive | Rapide |
Si on démarrait un nouveau projet NestJS aujourd'hui : Prisma pour les projets avec beaucoup de relations complexes et une équipe qui valorise la DX. TypeORM pour les projets qui ont besoin de soft deletes natifs, de migrations de données flexibles, ou qui préfèrent le module officiel @nestjs/typeorm à un service Prisma écrit à la main.
En pratique, les deux font le job. Le choix dépend plus de l'équipe que de la technologie.
Stack concernée : NestJS, PostgreSQL, TypeORM 0.2-0.3, Prisma 5
Ce contenu vous a servi ? Ajoutez Bob le développeur à vos sources préférées sur Google.
Renfort
Besoin de renfort dans votre équipe ?
Des développeurs React, Next.js et Node.js seniors, intégrés à vos sprints et à vos revues de code.
- Démarrage en quelques jours
- Engagement au mois
30 min, gratuit, sans engagement.