Introduction
Drizzle ORM est un ORM léger et performant pour TypeScript, conçu pour les développeurs qui veulent écrire du SQL type-safe sans sacrifier la flexibilité. Contrairement à Prisma qui génère du JS, Drizzle compile vos schémas en requêtes SQL natives, offrant une vitesse optimale et une intégration parfaite avec PostgreSQL, MySQL ou SQLite.
Pourquoi l'utiliser en 2026 ? Les apps modernes exigent des performances élevées et une sécurité type-safe. Drizzle excelle dans les projets Next.js, Vercel ou Deno, avec un bundle zero et des migrations automatisées via Drizzle Kit. Ce tutoriel beginner vous guide pour créer une base users complète : schéma, migrations, CRUD. À la fin, vous aurez un projet fonctionnel, prêt à scaler. Imaginez comme un 'SQL avec superpouvoirs TypeScript' – simple, rapide, puissant. (128 mots)
Prérequis
- Node.js 20+ installé
- Connaissances de base en TypeScript
- Un éditeur comme VS Code avec extension Drizzle
- Pas de base de données externe : on utilise SQLite pour simplicité
Initialiser le projet
mkdir drizzle-tutorial
cd drizzle-tutorial
npm init -y
npm install drizzle-orm better-sqlite3
dnpm install -D drizzle-kit typescript @types/node tsxOn crée un nouveau projet Node.js et installe Drizzle ORM avec better-sqlite3 pour une DB locale sans setup. Les dev deps incluent drizzle-kit pour migrations et tsx pour exécuter TS directement. Cela prépare un environnement minimaliste et fonctionnel.
Configurer TypeScript
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"outDir": "./dist",
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["./src/**/*"],
"exclude": ["node_modules", "dist"]
}Ce tsconfig.json standard active le mode strict et ES2022 pour compatibilité moderne. Il prépare le terrain pour les schémas Drizzle type-safe, évitant les erreurs de typage courantes dès le départ.
Définir le schéma de base
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
export const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
email: text('email').notNull().unique(),
});
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;On définit une table 'users' avec id auto-incrémenté, name et email unique. Les types User et NewUser sont inférés automatiquement pour type-safety totale. C'est la fondation : Drizzle transforme ce schéma en SQL valide.
Configurer Drizzle Kit
import type { Config } from 'drizzle-kit';
export default {
schema: './src/schema.ts',
out: './drizzle',
dialect: 'sqlite',
dbCredentials: {
url: './sqlite.db',
},
} satisfies Config;Ce fichier configure Drizzle Kit pour générer des migrations SQL à partir du schéma. Il pointe vers SQLite local (fichier sqlite.db créé auto). Dialect 'sqlite' assure compatibilité parfaite sans serveur externe.
Générer et appliquer migrations
npx drizzle-kit generate
npx drizzle-kit migrateLa première commande génère un fichier SQL dans /drizzle basé sur schema.ts. La seconde l'exécute sur sqlite.db, créant la table users. Toujours exécuter generate avant migrate pour détecter les changements de schéma.
Connexion à la DB et requête SELECT
import Database from 'better-sqlite3';
import { drizzle } from 'drizzle-orm/better-sqlite3';
import { users } from './schema';
const sqlite = new Database('./sqlite.db');
export const db = drizzle(sqlite, { schema: { users } });On connecte Drizzle à SQLite via better-sqlite3. L'export db est réutilisable partout. Le schema option infuse les types pour des queries intellisensées.
Implémenter CRUD complet
import { db } from './db';
import { users, type NewUser } from './schema';
import { eq } from 'drizzle-orm';
// INSERT
async function createUser(newUser: NewUser) {
return await db.insert(users).values(newUser).returning();
}
// SELECT all
async function getAllUsers() {
return await db.select().from(users);
}
// SELECT by ID
async function getUserById(id: number) {
return await db.select().from(users).where(eq(users.id, id)).limit(1);
}
// UPDATE
async function updateUser(id: number, updates: Partial<NewUser>) {
return await db.update(users).set(updates).where(eq(users.id, id)).returning();
}
// DELETE
async function deleteUser(id: number) {
return await db.delete(users).where(eq(users.id, id));
}
export { createUser, getAllUsers, getUserById, updateUser, deleteUser };Ce module implémente INSERT, SELECT, UPDATE et DELETE avec eq pour WHERE type-safe. .returning() renvoie les données modifiées. Partial
Script d'exécution et test
import { createUser, getAllUsers, getUserById, updateUser, deleteUser } from './index';
async function main() {
// Create
const newUser = await createUser({ name: 'Alice', email: 'alice@example.com' });
console.log('Created:', newUser);
// Read all
const allUsers = await getAllUsers();
console.log('All users:', allUsers);
// Read one
const user = await getUserById(1);
console.log('User 1:', user);
// Update
await updateUser(1, { name: 'Alice Updated' });
console.log('Updated user:', await getUserById(1));
// Delete
await deleteUser(1);
console.log('After delete:', await getAllUsers());
}
main().catch(console.error);Ce script teste tout le CRUD en séquence. Exécutez-le avec 'npx tsx src/main.ts' pour voir les résultats en console. Il démontre la fluidité : pas de boilerplate, queries composables.
Exécuter le projet
npx tsx src/main.tsCette commande lance le script de test. Vous verrez la DB se remplir, les queries s'exécuter et tout se nettoyer. Parfait pour valider que tout fonctionne sans erreur.
Bonnes pratiques
- Toujours utiliser les types inférés : User et NewUser évitent 90% des bugs runtime.
- Migrations en CI/CD : Intégrez 'drizzle-kit generate && migrate' dans vos pipelines.
- Transactions pour batches : db.transaction(async tx => { tx.insert... }) pour atomicité.
- Relations pour schémas complexes : Ajoutez pgTable.relations() dès le début.
- Environnement vars pour prod : Remplacez './sqlite.db' par process.env.DATABASE_URL.
Erreurs courantes à éviter
- Oublier 'npx drizzle-kit generate' avant migrate : mène à des schémas désynchronisés.
- Utiliser raw SQL sans eq() : perd la type-safety, risque d'injections.
- Pas de .returning() sur INSERT/UPDATE : impossible de récupérer l'ID généré.
- Ignorer les locks SQLite en prod : passez à PostgreSQL avec neon ou vercel/postgres pour concurrency.
Pour aller plus loin
Maîtrisez les relations et indexes avec docs Drizzle. Migrez vers PostgreSQL pour prod. Découvrez nos formations Learni sur les bases de données pour Next.js + Drizzle avancé.