Guide pratique Drizzle ORM : un ORM TypeScript 90 % plus léger que Prisma

La semaine dernière, j’ai déployé le projet sur Vercel. La page d’accueil a mis 3 secondes à s’afficher. Trois secondes ! Les utilisateurs sont déjà partis.
J’ouvre l’analyse de bundle Vercel et je fixe ce paquet Prisma Client de 14 Mo. Juste une requête utilisateur simple — pourquoi charger autant de code ? Pire encore : le cold start Lambda est insupportable — 600 ms sans Prisma, 2,5 s avec.
Vous allez me dire : Prisma n’est pas pratique ? Si, je le pensais aussi. Typage sûr, migrations auto, Prisma Studio — tout y est. Mais le problème, c’est qu’il est trop lourd.
Si vous vivez la même chose — cold start lent en serverless, bundle trop gros, requêtes complexes en raw SQL — cet article est pour vous. Aujourd’hui je présente Drizzle ORM : cœur de 7,4 ko, plus de 90 % plus léger que Prisma, avec la même sûreté de typage.
On configurera Next.js + Drizzle from scratch, on verra l’API SQL-like en action, et on comparera en profondeur Drizzle et Prisma. Surtout : quand choisir Drizzle, et quand Prisma reste le meilleur choix.
Pourquoi Drizzle ? Les limites des ORM actuels
Les trois points faibles de Prisma
Honnêtement, Prisma convient dans beaucoup de cas. Mais à l’usage, certains problèmes sont difficiles à contourner.
Point faible 1 : bundle incontrôlable
Le Client généré Prisma v5 peut atteindre 14 Mo. Votre projet Next.js entier fait peut-être 2–3 Mo — Prisma à lui seul en prend presque la moitié. Prisma 7 a réduit à ~1 Mo (sans binaire Rust), mais sur une vieille version ou si le bundle est critique, c’est un vrai souci.
Notre équipe avait une app de chat temps réel sur Cloudflare Workers — limite 1 Mo. Prisma dépassait la limite. Il a fallu changer d’approche.
Point faible 2 : cold start serverless lent
Sur GitHub, l’Issue #10724 traîne depuis des années : cold start Lambda Prisma trop lent. Les chiffres :
- Sans ORM : ~600 ms
- Avec Prisma v5 : ~2,5 s
- Avec Prisma v7 : ~1,5 s (mieux, mais toujours lent)
Prisma doit parser au démarrage une énorme chaîne DMMF (Data Model Meta Format). Pour un schema moyen : plus de 6 millions de caractères. Parsing à chaque cold start — forcément lent.
Cal.com a publié un article technique sur l’optimisation du cold start. Conclusion : le problème est réel ; on ne peut que le atténuer avec des contournements.
Point faible 3 : contrôle SQL insuffisant
La philosophie Prisma : « abstraire le SQL » via le DSL du Client. Pratique en général, mais pour les requêtes complexes, c’est bloquant.
JOINs multiples + sous-requêtes + agrégations conditionnelles — l’API Prisma ne suffit parfois pas. Il reste prisma.$queryRaw et du SQL brut.
Si on finit par écrire du SQL, autant partir sur une API SQL-like dès le départ. C’est l’idée de Drizzle.
Ce que les développeurs veulent vraiment
En résumé :
- Typage sûr sans sacrifier la perf : inférence TypeScript oui, mais pas ralentir le projet
- SQL direct, pas de nouveau DSL : SQL suffit, pas besoin d’apprendre la syntaxe Prisma
- Compatible serverless : en 2025, qui n’utilise pas Vercel, Cloudflare Workers ou AWS Lambda ?
- Compilation rapide : sur gros projets, l’inférence Prisma ralentit TypeScript — coût caché
Drizzle répond à ces besoins.
Drizzle ORM : qu’est-ce que c’est ?
La philosophie de Drizzle
Le slogan de Drizzle : « If you know SQL, you know Drizzle ». Un peu arrogant, mais fondé.
"If you know SQL, you know Drizzle."
Les ORM traditionnels abstraient le SQL. Drizzle fait l’inverse — il ne masque pas le SQL, son API TypeScript s’en rapproche au maximum. Le code ressemble au SQL, avec typage complet.
Exemple :
// Requête Drizzle
await db
.select()
.from(posts)
.leftJoin(comments, eq(posts.id, comments.postId))
.where(eq(posts.id, 10))
// SQL généré
SELECT * FROM posts
LEFT JOIN comments ON posts.id = comments.post_id
WHERE posts.id = 10
Structure quasi identique. Quiconque connaît SQL comprend immédiatement.
Caractéristiques clés
1. Extrême légèreté
Le paquet drizzle-orm : 7,4 ko (min+gzip), zéro dépendance runtime. Comparaison :
- Drizzle : ~7,4 ko
- TypeORM : ~300 ko
- Prisma v7 : ~1 Mo
- Prisma v5 : ~14 Mo
Ce n’est pas le même ordre de grandeur.
2. TypeScript-First, sans génération de Client
Prisma exige prisma generate. Drizzle non.
Vous définissez le schema, TypeScript infère les types. IntelliSense, vérification, erreurs — tout à la compilation.
3. API SQL-like, courbe quasi nulle
Si vous savez SQL, moins de 10 minutes pour démarrer.
// SELECT
db.select().from(users).where(eq(users.id, 1))
// INSERT
db.insert(users).values({ name: 'John', email: '[email protected]' })
// UPDATE
db.update(users).set({ name: 'Jane' }).where(eq(users.id, 1))
// DELETE
db.delete(users).where(eq(users.id, 1))
Pas besoin de doc si vous connaissez SQL.
4. Performance sans surcoût
Pas de couche d’abstraction runtime. Les requêtes deviennent du SQL directement.
Prisma parse le DMMF au démarrage et maintient un état interne. Drizzle est un pur query builder. Pas de coût caché.
5. Serverless-Ready
Environnements supportés :
- Vercel Edge Functions
- Cloudflare Workers
- AWS Lambda
- Deno Deploy
- Bun
Drivers serverless natifs :
- Neon Serverless
- PlanetScale
- Turso (SQLite on the edge)
- Supabase
Notre stack Neon + Drizzle sur Vercel Edge : cold start de 2,5 s à 700 ms. Résultat concret.
Cas d’usage
Drizzle n’est pas universel, mais il brille ici :
1. Applications serverless
Lambda, Edge Functions — légèreté et cold start rapide sont essentiels.
2. Scénarios sensibles à la performance
Temps réel, finance, analytics — la latence compte ; zéro abstraction apporte un gain réel.
3. Projets avec SQL complexe
Beaucoup de requêtes avancées, optimisation manuelle — l’API SQL-like bat le DSL Prisma.
4. Projets sensibles à la taille du bundle
Certains frameworks full-stack (SolidStart, Qwik) embarquent l’ORM côté client. 7,4 ko, c’est un avantage énorme.
Inversement : équipe peu à l’aise avec SQL, prototypage rapide, ou attachement à l’écosystème Prisma (Studio, Migrate, Pulse) — Prisma peut rester le meilleur choix.
Configuration Next.js + Drizzle en pratique
Assez de théorie. Configurons un projet Next.js 15 + Drizzle + PostgreSQL from scratch.
Préparation de l’environnement
Créer le projet Next.js :
npx create-next-app@latest my-drizzle-app
cd my-drizzle-app
Installer Drizzle :
npm install drizzle-orm drizzle-kit
npm install @neondatabase/serverless # avec Neon
# ou
npm install postgres # PostgreSQL classique
Je recommande Neon — PostgreSQL serverless, excellent avec Drizzle. Compte gratuit, créer une base, récupérer la chaîne de connexion.
Définir le schema
Créer db/schema.ts :
import { pgTable, serial, text, timestamp, integer } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
// Table utilisateurs
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
createdAt: timestamp('created_at').defaultNow(),
});
// Table articles
export const posts = pgTable('posts', {
id: serial('id').primaryKey(),
title: text('title').notNull(),
content: text('content'),
authorId: integer('author_id').references(() => users.id),
createdAt: timestamp('created_at').defaultNow(),
});
// Relations (one-to-many)
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}));
Du TypeScript pur. Pas de fichier schema Prisma, pas de Client à générer.
Connexion à la base
Créer db/index.ts :
import { drizzle } from 'drizzle-orm/neon-http';
import { neon } from '@neondatabase/serverless';
import * as schema from './schema';
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql, { schema });
Dans .env.local :
DATABASE_URL=postgres://user:[email protected]/dbname
Drizzle Kit (migrations)
Créer drizzle.config.ts :
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './db/schema.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
Générer les migrations :
npx drizzle-kit generate
Fichiers SQL dans drizzle/. Vérifier, puis :
npx drizzle-kit push
Les tables sont créées.
Structure finale
my-drizzle-app/
├── app/ # Application Next.js
│ ├── page.tsx
│ └── actions.ts # Server Actions
├── db/
│ ├── schema.ts # Tables et relations
│ └── index.ts # Connexion
├── drizzle/
│ └── migrations/ # Migrations (auto)
├── drizzle.config.ts
├── .env.local
└── package.json
Moins de 5 minutes. Pas de syntaxe Prisma Schema, pas de long prisma generate — du TypeScript pur.
API SQL-like de Drizzle en pratique
Configuration faite. Voyons les requêtes courantes et leur usage dans les Server Actions Next.js.
CRUD de base
SELECT
import { db } from '@/db';
import { users, posts } from '@/db/schema';
import { eq, like, and, or, desc } from 'drizzle-orm';
const allUsers = await db.select().from(users);
const user = await db.select().from(users).where(eq(users.id, 1));
const result = await db.select().from(users).where(like(users.name, '%John%'));
const admins = await db
.select()
.from(users)
.where(
and(
eq(users.role, 'admin'),
gt(users.createdAt, new Date('2024-01-01'))
)
);
const latestPosts = await db
.select()
.from(posts)
.orderBy(desc(posts.createdAt))
.limit(10);
La logique SQL, en appels de fonctions.
INSERT
await db.insert(users).values({
name: 'John Doe',
email: '[email protected]',
});
await db.insert(users).values([
{ name: 'Alice', email: '[email protected]' },
{ name: 'Bob', email: '[email protected]' },
]);
const [newUser] = await db
.insert(users)
.values({ name: 'Charlie', email: '[email protected]' })
.returning();
console.log(newUser.id);
UPDATE
await db
.update(users)
.set({ name: 'Jane Doe' })
.where(eq(users.id, 1));
await db
.update(posts)
.set({ published: true })
.where(eq(posts.authorId, 1));
const [updatedUser] = await db
.update(users)
.set({ name: 'Updated Name' })
.where(eq(users.id, 1))
.returning();
DELETE
await db.delete(users).where(eq(users.id, 1));
await db.delete(posts).where(eq(posts.published, false));
const deleted = await db
.delete(users)
.where(eq(users.id, 1))
.returning();
Requêtes avancées
JOIN
const usersWithPosts = await db
.select({
userId: users.id,
userName: users.name,
postId: posts.id,
postTitle: posts.title,
})
.from(users)
.leftJoin(posts, eq(users.id, posts.authorId));
const activeAuthors = await db
.select()
.from(users)
.innerJoin(posts, eq(users.id, posts.authorId));
Sous-requêtes
const sq = db
.select({ authorId: posts.authorId, count: count() })
.from(posts)
.groupBy(posts.authorId)
.having(gt(count(), 5))
.as('sq');
const prolificAuthors = await db
.select()
.from(users)
.innerJoin(sq, eq(users.id, sq.authorId));
Agrégations
import { count, sum, avg } from 'drizzle-orm';
const [{ total }] = await db
.select({ total: count() })
.from(users);
const postCounts = await db
.select({
authorId: posts.authorId,
count: count(),
})
.from(posts)
.groupBy(posts.authorId);
Server Actions Next.js
Créer app/actions.ts :
'use server';
import { db } from '@/db';
import { users } from '@/db/schema';
import { eq } from 'drizzle-orm';
import { revalidatePath } from 'next/cache';
export async function createUser(formData: FormData) {
const name = formData.get('name') as string;
const email = formData.get('email') as string;
try {
await db.insert(users).values({ name, email });
revalidatePath('/users');
return { success: true };
} catch (error) {
return { success: false, error: 'Échec de la création de l\'utilisateur' };
}
}
export async function getUsers() {
return await db.select().from(users);
}
export async function deleteUser(id: number) {
try {
await db.delete(users).where(eq(users.id, id));
revalidatePath('/users');
return { success: true };
} catch (error) {
return { success: false, error: 'Échec de la suppression de l\'utilisateur' };
}
}
Dans la page :
// app/users/page.tsx
import { getUsers } from '../actions';
export default async function UsersPage() {
const users = await getUsers();
return (
<div>
<h1>Liste des utilisateurs</h1>
<ul>
{users.map(user => (
<li key={user.id}>
{user.name} - {user.email}
</li>
))}
</ul>
</div>
);
}
Sûreté de typage TypeScript
Le point fort de Drizzle — inférence complète.
const users = await db.select().from(users);
// Type : { id: number; name: string; email: string; createdAt: Date }[]
const result = await db
.select({
id: users.id,
name: users.name,
})
.from(users);
// Type : { id: number; name: string }[]
await db.select().from(users).where(eq(users.id, '1'));
// ❌ Erreur TypeScript : le type 'string' n'est pas assignable au type 'number'
IntelliSense pour champs, fonctions, opérateurs. Le compilateur TypeScript suffit comme documentation.
Drizzle vs Prisma : comparaison approfondie
Objectivons avec une comparaison complète pour choisir en connaissance de cause.
Performance
| Dimension | Drizzle | Prisma v5 | Prisma v7 | Note |
|---|---|---|---|---|
| Taille bundle | ~7,4 ko | ~14 Mo | ~1 Mo | Drizzle le plus léger |
| Cold start | ~600 ms | ~2,5 s | ~1,5 s | Environnement serverless |
| Dépendances runtime | 0 | Binaire Rust | 0 | Drizzle et Prisma v7 sans dépendance |
| Mémoire | ~5 Mo | ~80 Mo | ~30 Mo (est.) | Mémoire à l’exécution |
| Vitesse typage | Rapide | Moyenne | Moyenne | Inférence Drizzle plus simple |
Données réelles
Après migration Prisma v5 → Drizzle :
- Première requête : 3 s → 700 ms (−76 %)
- Bundle production : 18 Mo → 4 Mo (−78 %)
- Cold start Lambda : 2,4 s → 650 ms (−73 %)
Monitoring production, pas benchmarks de labo.
Expérience de développement
Définition du schema
// Drizzle (TypeScript)
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
});
// Prisma (DSL dédié)
model User {
id Int @id @default(autoincrement())
name String
}
Drizzle : TypeScript natif, IDE, types avancés (conditionnels, génériques)
Prisma : schema plus concis et lisible
Style de requête
// Drizzle (SQL-like)
await db
.select()
.from(users)
.leftJoin(posts, eq(users.id, posts.authorId))
.where(gt(posts.views, 1000));
// Prisma (API chaînée)
await prisma.user.findMany({
include: {
posts: {
where: { views: { gt: 1000 } },
},
},
});
Drizzle : plus proche du SQL, requêtes complexes plus expressives
Prisma : plus accessible sans SQL, requêtes imbriquées plus claires
Comparaison fonctionnelle
Atouts Drizzle
- Extrême légèreté : 7,4 ko, idéal si le bundle compte
- Serverless natif : cold start rapide, Edge
- Contrôle SQL : requêtes complexes, optimisation flexible
- Sans génération de Client : modifier le schema et coder
- Tree-shakable : seul le code utilisé est embarqué
Atouts Prisma
- Écosystème mature : depuis 2021, grande communauté
- Outils complets : Studio, Migrate, Pulse
- Requêtes relationnelles intelligentes : N+1, imbrication intuitive
- Accessible aux débutants : pas besoin de maîtriser SQL
- Messages d’erreur détaillés au runtime
Recommandations
Choisir Drizzle
✅ Serverless/Edge (Vercel, Cloudflare Workers, Deno Deploy)
✅ Performance critique (temps réel, finance, API à fort trafic)
✅ Bundle limité (< 1 Mo)
✅ Équipe à l’aise avec SQL
✅ Optimisations SQL avancées
Choisir Prisma
✅ Équipe peu familière avec SQL
✅ Outillage complet prioritaire
✅ Gestion visuelle (Prisma Studio)
✅ Modélisation et relations complexes
✅ Hors serverless, bundle peu contraint
Mon avis
Pour un nouveau projet :
- Projet perso / startup : Drizzle (perf, coût, optimisation)
- Entreprise / équipe : selon le niveau SQL — fort → Drizzle, faible → Prisma
- Serverless-First : Drizzle sans hésiter
- Serveur traditionnel : les deux conviennent ; Prisma a l’outillage le plus abouti
Approche hybride possible : Drizzle pour les modules perf-critiques, Prisma pour l’admin. Coexistence sans conflit.
Migration et bonnes pratiques
Migrer de Prisma vers Drizzle
Migration progressive si vous avez déjà Prisma.
Étape 1 : conversion du schema
// Prisma Schema
model User {
id Int @id @default(autoincrement())
name String
email String @unique
posts Post[]
createdAt DateTime @default(now())
}
// Drizzle Schema
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
createdAt: timestamp('created_at').defaultNow(),
});
Étape 2 : réécriture des requêtes
// Prisma
const user = await prisma.user.findUnique({
where: { id: 1 },
include: { posts: true },
});
// Drizzle
const [user] = await db
.select()
.from(users)
.where(eq(users.id, 1))
.leftJoin(posts, eq(users.id, posts.authorId));
Étape 3 : remplacement progressif
Prisma et Drizzle en parallèle :
import { db } from '@/db/drizzle';
const latestPosts = await db
.select()
.from(posts)
.orderBy(desc(posts.createdAt))
.limit(50);
import { prisma } from '@/db/prisma';
const userWithRelations = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: { include: { comments: { include: { author: true } } } },
},
});
Remplacement étape par étape pour limiter les risques.
Bonnes pratiques Drizzle
1. Pool de connexions
En serverless, attention au pool :
import { drizzle } from 'drizzle-orm/neon-http';
import { neon, neonConfig } from '@neondatabase/serverless';
neonConfig.fetchConnectionCache = true;
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql, { schema });
2. Requêtes précompilées
Pour les requêtes fréquentes :
import { db } from '@/db';
import { users } from '@/db/schema';
import { eq } from 'drizzle-orm';
const getUserById = db
.select()
.from(users)
.where(eq(users.id, placeholder('id')))
.prepare('get_user_by_id');
const user = await getUserById.execute({ id: 1 });
3. Transactions
await db.transaction(async (tx) => {
const [user] = await tx
.insert(users)
.values({ name: 'John', email: '[email protected]' })
.returning();
await tx.insert(posts).values({
title: 'First Post',
authorId: user.id,
});
});
4. Réutilisation des types
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull(),
});
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;
import type { User } from '@/db/schema';
function UserCard({ user }: { user: User }) {
return <div>{user.name}</div>;
}
5. Gestion des erreurs
import { db } from '@/db';
import { users } from '@/db/schema';
try {
await db.insert(users).values({
name: 'John',
email: '[email protected]',
});
} catch (error) {
if (error.code === '23505') {
console.error('L\'adresse e-mail existe déjà');
} else {
console.error('Erreur de base de données', error);
}
}
Conclusion
Drizzle ORM apporte du frais dans les ORM TypeScript — il n’abstrait pas le SQL, il l’embrasse. Avec 7,4 ko, zéro dépendance runtime et des performances proches du SQL natif, la légèreté n’est pas un compromis, c’est un choix supérieur.
Ce n’est pas un remplacement total de Prisma. Prisma a un écosystème plus mature, une chaîne d’outils plus complète, une meilleure accueil pour les débutants. Mais si votre projet :
- tourne en serverless
- est sensible à la perf et au bundle
- nécessite un contrôle SQL avancé
- a une équipe à l’aise avec SQL
Drizzle est probablement le meilleur choix.
Nos chiffres parlent : cold start −73 %, bundle −78 %, première requête de 3 s à 700 ms. Ce n’est pas une micro-optimisation, c’est un saut qualitatif.
Si le cold start lent et le gros bundle Prisma vous freinent, essayez Drizzle. Courbe d’apprentissage faible — 10 minutes si vous connaissez SQL.
Liens utiles :
- Documentation officielle Drizzle ORM
- Dépôt GitHub Drizzle
- Exemple officiel Next.js + Drizzle
- Comparaison officielle Drizzle vs Prisma
Essayez — vous ne reviendrez peut-être plus en arrière.
Configuration complète Next.js + Drizzle ORM et guide de migration
Configuration Drizzle ORM from scratch : environnement, schema, connexion, requêtes et migration depuis Prisma
Estimated time: PT2H
-
1
Step 1: Étape 1 : environnement et dépendances
Créer le projet Next.js : -
2
Step 2: • Compte gratuit
https://neon.tech -
3
Step 3: Étape 2 : définir le schema
Créer db/schema.ts : -
4
Step 4: Étape 3 : connexion et Drizzle Kit
Créer db/index.ts : -
5
Step 5: Étape 4 : requêtes avec l’API SQL-like
CRUD de base : -
6
Step 6: Étape 5 : Server Actions Next.js
Créer app/actions.ts : -
7
Step 7: {user.name}
{user.email} -
8
Step 8: Étape 6 : migration depuis Prisma (optionnel)
Migration progressive si projet Prisma existant :
FAQ
Quelle est la différence entre Drizzle ORM et Prisma ? Quand choisir Drizzle ?
Performance :
• Drizzle : 7,4 ko, cold start 600 ms, zéro dépendance runtime
• Prisma v5 : 14 Mo, cold start 2,5 s, binaire Rust requis
• Prisma v7 : 1 Mo, cold start 1,5 s, optimisé mais toujours plus lent que Drizzle
Expérience de développement :
• Drizzle : API SQL-like, si vous connaissez SQL vous connaissez Drizzle, pas de génération de Client
• Prisma : DSL dédié à apprendre, nécessite prisma generate
Choisir Drizzle :
✅ Environnements serverless/Edge (Vercel, Cloudflare Workers, Deno Deploy)
✅ Scénarios sensibles à la performance (apps temps réel, finance, API à fort trafic)
✅ Bundle limité (environnements < 1 Mo)
✅ Équipe à l'aise avec SQL, contrôle direct des requêtes
✅ Projets nécessitant des optimisations SQL complexes
Choisir Prisma :
✅ Équipe peu familière avec SQL, besoin de démarrer vite
✅ Priorité à l'expérience dev et à la chaîne d'outils complète
✅ Gestion visuelle de la base (Prisma Studio)
✅ Requêtes relationnelles et modélisation de données complexes
✅ Projet hors serverless, bundle peu contraint
Que signifie concrètement l'API SQL-like de Drizzle ORM ?
Comparaison :
SQL :
```sql
SELECT * FROM posts
LEFT JOIN comments ON posts.id = comments.post_id
WHERE posts.id = 10
```
Drizzle :
```typescript
await db
.select()
.from(posts)
.leftJoin(comments, eq(posts.id, comments.postId))
.where(eq(posts.id, 10))
```
Points clés :
• Structure quasi identique au SQL
• Quiconque connaît SQL comprend immédiatement
• Courbe d'apprentissage quasi nulle (si vous savez SQL)
• Inférence de types complète, complétion IntelliSense
• Erreurs détectées à la compilation
Comparé au DSL Prisma :
```typescript
// Prisma impose une nouvelle syntaxe de requête
await prisma.user.findMany({
include: {
posts: {
where: { views: { gt: 1000 } },
},
},
});
```
Drizzle reste plus proche du SQL natif ; les requêtes complexes s'expriment plus facilement.
Quel est l'avantage performance de Drizzle ORM en serverless ?
Gains :
• Temps de première requête : 3 s → 700 ms (76 % plus rapide)
• Bundle production : 18 Mo → 4 Mo (−78 %)
• Cold start Lambda : 2,4 s → 650 ms (−73 %)
Analyse :
1. Taille du bundle :
• Cœur Drizzle : 7,4 ko (min+gzip)
• Client généré Prisma v5 : jusqu'à 14 Mo
• Sur Cloudflare Workers (limite 1 Mo), Prisma dépasse la limite
2. Cold start :
• Prisma parse au démarrage une énorme chaîne DMMF (Data Model Meta Format)
• Pour un schema moyen : plus de 6 millions de caractères
• Parsing à chaque cold start → lenteur
• Drizzle : pas de couche d'abstraction runtime, requêtes traduites directement en SQL
3. Mémoire :
• Drizzle : ~5 Mo
• Prisma v5 : ~80 Mo
• Prisma v7 : ~30 Mo (estimation)
Ces chiffres proviennent du monitoring production, pas de benchmarks artificiels.
Comment migrer de Prisma vers Drizzle ? La migration est-elle complexe ?
Étape 1 : conversion du schema
Prisma Schema → Drizzle Schema :
• model Prisma → définition pgTable
• Types : Int → serial/integer, String → text, DateTime → timestamp
• Relations : syntaxe Prisma → fonction relations Drizzle
Étape 2 : réécriture des requêtes
Prisma → Drizzle :
• findUnique/findMany → select().from().where()
• include → leftJoin/innerJoin
• create → insert().values()
• update → update().set().where()
Étape 3 : remplacement progressif
Prisma et Drizzle peuvent coexister :
```typescript
// Requêtes sensibles à la perf : Drizzle
import { db } from '@/db/drizzle';
const latestPosts = await db
.select()
.from(posts)
.orderBy(desc(posts.createdAt))
.limit(50);
// Requêtes relationnelles complexes : Prisma temporairement
import { prisma } from '@/db/prisma';
const userWithRelations = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: { include: { comments: { include: { author: true } } } },
},
});
```
Remplacement étape par étape pour limiter les risques. La migration reste surtout une conversion de syntaxe.
Quelles bases de données Drizzle ORM supporte-t-il ? Dans quels environnements ?
• PostgreSQL (Neon Serverless recommandé)
• MySQL
• SQLite (dont Turso, SQLite on the edge)
• SQL Server
Environnements serverless :
• Vercel Edge Functions
• Cloudflare Workers
• AWS Lambda
• Deno Deploy
• Bun
Drivers serverless natifs :
• Neon Serverless (PostgreSQL)
• PlanetScale (MySQL)
• Turso (SQLite on the edge)
• Supabase (PostgreSQL)
Notre projet utilise Neon + Drizzle sur Vercel Edge : cold start passé de 2,5 s à 700 ms.
Atouts :
• Tous les environnements serverless majeurs
• Drivers serverless natifs
• Zéro dépendance runtime, exécutable dans tout environnement JavaScript
Quelle est la sûreté de typage de Drizzle ORM comparée à Prisma ?
Inférence :
Drizzle (automatique) :
```typescript
// Type de retour inféré automatiquement
const users = await db.select().from(users);
// Type : { id: number; name: string; email: string; createdAt: Date }[]
// Champs personnalisés, types inférés
const result = await db
.select({
id: users.id,
name: users.name,
})
.from(users);
// Type : { id: number; name: string }[]
// Erreur capturée à la compilation
await db.select().from(users).where(eq(users.id, '1'));
// ❌ Erreur TypeScript : le type 'string' n'est pas assignable au type 'number'
```
Points clés :
• Pas de Client généré, TypeScript infère directement
• IntelliSense pour champs, fonctions, opérateurs
• Détection à la compilation, pas au runtime
• Vérification de types plus rapide (inférence plus simple)
Comparé à Prisma :
• Prisma exige prisma generate
• Sur gros projets, l'inférence Prisma ralentit la compilation TypeScript
• Drizzle : inférence plus légère, compilation plus rapide
Exporter les types pour le frontend :
```typescript
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;
```
Drizzle ORM convient-il aux débutants ? Quelle courbe d'apprentissage ?
Temps de prise en main :
• Avec SQL : opérationnel en 10 minutes
• Sans SQL : bases SQL requises d'abord
Pourquoi c'est accessible :
• API SQL-like, structure quasi identique au SQL
• Pas de nouveau DSL (contrairement à Prisma)
• Complétion IntelliSense complète
• Le compilateur TypeScript sert de documentation
Exemples :
```typescript
// SELECT
db.select().from(users).where(eq(users.id, 1))
// INSERT
db.insert(users).values({ name: 'John', email: '[email protected]' })
// UPDATE
db.update(users).set({ name: 'Jane' }).where(eq(users.id, 1))
// DELETE
db.delete(users).where(eq(users.id, 1))
```
Quiconque connaît SQL n'a pas besoin de consulter la doc.
Comparé à Prisma :
• Prisma : DSL dédié à apprendre
• Plus friendly pour qui ne connaît pas SQL
• Mais si vous maîtrisez SQL, Drizzle est plus intuitif
Conseil :
• Équipe forte en SQL : Drizzle directement
• Équipe faible en SQL : Prisma, ou apprendre SQL puis Drizzle
14 min de lecture · Publié le: 20 déc. 2025 · Mis à jour le: 27 juil. 2026
Guide complet Next.js
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
Guide complet SWR : maîtriser les stratégies de cache et les mises à jour optimistes en pratique
Apprenez les concepts clés et les stratégies de cache de SWR, et simplifiez jusqu'à 90 % de votre code de récupération de données avec un seul Hook. Inclut des exemples pratiques de mises à jour optimistes, une comparaison avec React Query et les bonnes pratiques d'intégration Next.js.
Partie 50 sur 51
Suivant
C’est le dernier article publié dans cette série pour le moment.



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire