Changer le thème

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

Easton editorial illustration: component assembly loom

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é :

  1. Typage sûr sans sacrifier la perf : inférence TypeScript oui, mais pas ralentir le projet
  2. SQL direct, pas de nouveau DSL : SQL suffit, pas besoin d’apprendre la syntaxe Prisma
  3. Compatible serverless : en 2025, qui n’utilise pas Vercel, Cloudflare Workers ou AWS Lambda ?
  4. 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

~7,4ko
Bundle Drizzle
vs Prisma 14 Mo
~600ms
Cold start
vs Prisma 2,5 s
0
Dépendances runtime
TypeScript pur
Source: Données monitoring production
DimensionDrizzlePrisma v5Prisma v7Note
Taille bundle~7,4 ko~14 Mo~1 MoDrizzle le plus léger
Cold start~600 ms~2,5 s~1,5 sEnvironnement serverless
Dépendances runtime0Binaire Rust0Drizzle et Prisma v7 sans dépendance
Mémoire~5 Mo~80 Mo~30 Mo (est.)Mémoire à l’exécution
Vitesse typageRapideMoyenneMoyenneInfé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

  1. Extrême légèreté : 7,4 ko, idéal si le bundle compte
  2. Serverless natif : cold start rapide, Edge
  3. Contrôle SQL : requêtes complexes, optimisation flexible
  4. Sans génération de Client : modifier le schema et coder
  5. Tree-shakable : seul le code utilisé est embarqué

Atouts Prisma

  1. Écosystème mature : depuis 2021, grande communauté
  2. Outils complets : Studio, Migrate, Pulse
  3. Requêtes relationnelles intelligentes : N+1, imbrication intuitive
  4. Accessible aux débutants : pas besoin de maîtriser SQL
  5. 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 :

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. 1

    Step 1: Étape 1 : environnement et dépendances

    Créer le projet Next.js :
  2. 2

    Step 2: • Compte gratuit

    https://neon.tech
  3. 3

    Step 3: Étape 2 : définir le schema

    Créer db/schema.ts :
  4. 4

    Step 4: Étape 3 : connexion et Drizzle Kit

    Créer db/index.ts :
  5. 5

    Step 5: Étape 4 : requêtes avec l’API SQL-like

    CRUD de base :
  6. 6

    Step 6: Étape 5 : Server Actions Next.js

    Créer app/actions.ts :
  7. 7

    Step 7: {user.name}

    {user.email}
  8. 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 ?
Différences principales :

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 ?
L'API Drizzle rapproche au maximum le code TypeScript de la syntaxe SQL :

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 ?
Données réelles (migration Prisma v5 → Drizzle) :

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 ?
Migration progressive possible, sans tout remplacer d'un coup :

É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 ?
Bases supportées :

• 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 ?
Drizzle offre une sûreté de typage complète, plus simple que 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 ?
Si vous connaissez SQL, la courbe est très douce :

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

Commentaires

Connectez-vous avec GitHub pour laisser un commentaire

Easton BlogEaston Blog