Drizzle ORM Praxisleitfaden: 90 % leichter als Prisma – die TypeScript-ORM-Wahl

Letzte Woche Deployment auf Vercel – Startseite 3 Sekunden Wartezeit. Drei Sekunden! Nutzer sind längst weg.
Im Vercel-Bundle-Analyse: ein Prisma-Client-Paket mit 14 MB. Einfache User-Queries – warum so viel Code? Schlimmer: Lambda Cold Start quälend – Funktionen ohne Prisma ~600 ms, mit Prisma 2,5 Sekunden.
Prisma sei doch gut? Stimmt – auch ich dachte das. Typsicherheit, Auto-Migration, Prisma Studio – alles da. Aber: es ist zu schwer.
Kennen Sie das? Serverless mit langsamem Cold Start, Bundle über Limit, komplexe Queries nur mit Raw SQL – dann ist dieser Artikel für Sie. Drizzle ORM: Kernpaket 7,4 kb, über 90 % leichter als Prisma, gleiche Typsicherheit.
Wir konfigurieren Next.js + Drizzle von null, erklären die SQL-like API und vergleichen Performance mit Prisma. Und: wann Drizzle, wann weiter Prisma.
Warum Drizzle? Schmerzpunkte bestehender ORMs
Drei Prisma-Schmerzpunkte
Prisma passt in vielen Fällen – aber drei Probleme bleiben hartnäckig.
Schmerzpunkt 1: Bundle außer Kontrolle
Prisma v5 Client bis 14 MB. Ihr ganzes Next.js-Projekt vielleicht 2–3 MB – Prisma allein fast die Hälfte. Prisma 7 reduziert auf ~1 MB (ohne Rust-Binary) – alte Versionen oder Bundle-Sensibilität bleiben kritisch.
Unser Echtzeit-Chat auf Cloudflare Workers: Limit 1 MB. Prisma scheiterte. Plan B nötig.
Schmerzpunkt 2: Langsamer Serverless Cold Start
GitHub Issue #10724 – jahrelang diskutiert: Prisma Lambda Cold Start zu langsam.
- Ohne ORM: ~600 ms
- Prisma v5: ~2,5 s
- Prisma v7: ~1,5 s (besser, aber noch langsam)
Ursache: Parsen eines riesigen DMMF-Strings beim Start. Mittlere Schemas: über 6 Mio. Zeichen – jeder Cold Start erneut.
Cal.com schrieb deshalb einen Blogpost zur Cold-Start-Optimierung. Fazit: Problem real, nur Workarounds.
Schmerzpunkt 3: Wenig SQL-Kontrolle
Prisma abstrahiert SQL – DSL statt SQL. Meist praktisch – bei komplexen Queries nicht.
Mehrstufige JOINs, Subqueries, bedingte Aggregation – Prisma API reicht oft nicht. Dann prisma.$queryRaw und handgeschriebenes SQL.
Warum nicht von Anfang an SQL-nah? Drizzles Ansatz.
Was Entwickler wirklich wollen
- Typsicherheit ohne Performance-Opfer
- SQL nutzen, keine neue DSL
- Serverless-tauglich (Vercel, Cloudflare Workers, Lambda)
- Schnelle Kompilierung – Prisma-Typen bremsen große Projekte
Drizzle zielt genau darauf.
Was ist Drizzle ORM? Kernmerkmale
Design-Philosophie
Slogan: „If you know SQL, you know Drizzle.“ – zutreffend.
"If you know SQL, you know Drizzle."
Klassische ORMs verstecken SQL. Drizzle nicht – TypeScript-API nahe an SQL, volle Typ-Hinweise.
Beispiel:
// Drizzle Query
await db
.select()
.from(posts)
.leftJoin(comments, eq(posts.id, comments.postId))
.where(eq(posts.id, 10))
// Generiertes SQL
SELECT * FROM posts
LEFT JOIN comments ON posts.id = comments.post_id
WHERE posts.id = 10
Struktur fast identisch mit SQL. Wer SQL kann, versteht es sofort.
Kernmerkmale
1. Extrem leicht
Kernpaket drizzle-orm: 7,4 kb (min+gzip), null Runtime-Abhängigkeiten.
- Drizzle: ~7,4 kb
- TypeORM: ~300 kb
- Prisma v7: ~1 MB
- Prisma v5: ~14 MB
Keine Größenordnung gleich.
2. TypeScript-First, kein Client-Generate
Prisma: prisma generate. Drizzle: nicht nötig.
Schema definieren – TypeScript inferiert Typen. IntelliSense, Typ-Checks, Fehler zur Compile-Zeit.
3. SQL-like API, Lernkosten nahe null
Mit SQL: unter 10 Minuten Einstieg.
// 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))
Wer SQL kann, braucht keine Docs.
4. Performance ohne Abstraktionskosten
Keine Runtime-Abstraktion – Queries werden direkt zu SQL. Kein DMMF-Parsing wie bei Prisma. Keine versteckten Kosten.
5. Serverless-Ready
Umgebungen:
- Vercel Edge Functions
- Cloudflare Workers
- AWS Lambda
- Deno Deploy
- Bun
Serverless-DB-Treiber:
- Neon Serverless
- PlanetScale
- Turso (SQLite on the Edge)
- Supabase
Unser Stack: Neon + Drizzle auf Vercel Edge – Cold Start 2,5 s → 700 ms.
Einsatzszenarien
1. Serverless
Lambda, Edge – Leichtgewicht und schneller Cold Start sind Pflicht.
2. Performancekritisch
Echtzeit, Finanz, Analytics – null Abstraktion zahlt sich aus.
3. Komplexe SQL-Kontrolle
Viele komplexe Queries, manuelle Optimierung – SQL-like schlägt Prisma DSL.
4. Bundle-sensitive Full-Stack-Projekte
SolidStart, Qwik – ORM im Client-Bundle. 7,4 kb vs. Megabytes.
Umgekehrt: wenig SQL im Team, schnelle Prototypen, Prisma Studio/Migrate/Pulse – Prisma kann besser passen.
Next.js + Drizzle: Praxis-Setup
Theorie reicht – wir bauen Next.js 15 + Drizzle + PostgreSQL von null.
Umgebung vorbereiten
Next.js-Projekt:
npx create-next-app@latest my-drizzle-app
cd my-drizzle-app
Drizzle-Abhängigkeiten:
npm install drizzle-orm drizzle-kit
npm install @neondatabase/serverless # für Neon
# oder
npm install postgres # klassisches PostgreSQL
Empfehlung: Neon – serverless PostgreSQL, ideal mit Drizzle. Gratis-Account, DB anlegen, Connection String kopieren.
Datenbank-Schema definieren
db/schema.ts:
import { pgTable, serial, text, timestamp, integer } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
// Benutzertabelle
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
createdAt: timestamp('created_at').defaultNow(),
});
// Artikeltabelle
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(),
});
// Relationen (1:n)
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}));
Reines TypeScript – kein Prisma-Schema, kein Client-Generate.
Datenbankverbindung
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 });
In .env.local:
DATABASE_URL=postgres://user:[email protected]/dbname
Drizzle Kit (Migrationen)
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!,
},
});
Migration erzeugen:
npx drizzle-kit generate
SQL in drizzle/ prüfen, dann:
npx drizzle-kit push
Tabellen stehen.
Projektstruktur
my-drizzle-app/
├── app/ # Next.js App
│ ├── page.tsx
│ └── actions.ts # Server Actions
├── db/
│ ├── schema.ts # Tabellen und Relationen
│ └── index.ts # DB-Verbindung
├── drizzle/
│ └── migrations/ # Migrationen (auto)
├── drizzle.config.ts # Drizzle Kit Config
├── .env.local # Umgebungsvariablen
└── package.json
Unter 5 Minuten – kein Prisma-Schema-Syntax, kein langes prisma generate, nur TypeScript.
Drizzle SQL-like API in der Praxis
Häufigste Operationen und Server Actions.
Basis-CRUD
SELECT
import { db } from '@/db';
import { users, posts } from '@/db/schema';
import { eq, like, and, or, desc } from 'drizzle-orm';
// Alle Benutzer
const allUsers = await db.select().from(users);
// Ein Benutzer
const user = await db.select().from(users).where(eq(users.id, 1));
// LIKE-Suche
const result = await db.select().from(users).where(like(users.name, '%John%'));
// Mehrere Bedingungen
const admins = await db
.select()
.from(users)
.where(
and(
eq(users.role, 'admin'),
gt(users.createdAt, new Date('2024-01-01'))
)
);
// Sortierung und Limit
const latestPosts = await db
.select()
.from(posts)
.orderBy(desc(posts.createdAt))
.limit(10);
SQL-Logik als Funktionsaufrufe.
INSERT
// Ein Datensatz
await db.insert(users).values({
name: 'John Doe',
email: '[email protected]',
});
// Mehrere
await db.insert(users).values([
{ name: 'Alice', email: '[email protected]' },
{ name: 'Bob', email: '[email protected]' },
]);
// Mit Rückgabe
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();
Erweiterte Queries
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));
Subquery
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));
Aggregation
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);
In Next.js Server Actions
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: 'Benutzer konnte nicht erstellt werden' };
}
}
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: 'Benutzer konnte nicht gelöscht werden' };
}
}
Seite:
// app/users/page.tsx
import { getUsers } from '../actions';
export default async function UsersPage() {
const users = await getUsers();
return (
<div>
<h1>Benutzerliste</h1>
<ul>
{users.map(user => (
<li key={user.id}>
{user.name} - {user.email}
</li>
))}
</ul>
</div>
);
}
TypeScript Typsicherheit
Volle Typ-Inferenz – Drizzles Stärke.
const users = await db.select().from(users);
// Typ: { id: number; name: string; email: string; createdAt: Date }[]
const result = await db
.select({
id: users.id,
name: users.name,
})
.from(users);
// Typ: { id: number; name: string }[]
await db.select().from(users).where(eq(users.id, '1'));
// ❌ TypeScript: string nicht zu number zuweisbar
IntelliSense für Felder, Funktionen, Operatoren. TypeScript-Compiler als Dokumentation.
Drizzle vs. Prisma: Tiefer Vergleich
Objektiv – damit Sie die richtige Wahl treffen.
Performance
| Dimension | Drizzle | Prisma v5 | Prisma v7 | Anmerkung |
|---|---|---|---|---|
| Bundle | ~7,4 kb | ~14 MB | ~1 MB | Drizzle am leichtesten |
| Cold Start | ~600 ms | ~2,5 s | ~1,5 s | Serverless |
| Runtime-Deps | 0 | Rust-Binary | 0 | Drizzle & v7 ohne Binary |
| Speicher | ~5 MB | ~80 MB | ~30 MB (geschätzt) | Laufzeit |
| Typ-Check-Geschwindigkeit | Schnell | Mittel | Mittel | Einfachere Inferenz |
Reale Fallzahlen
Migration Prisma v5 → Drizzle:
- Erste Anfrage: 3 s → 700 ms (76 % schneller)
- Produktions-Bundle: 18 MB → 4 MB (78 % kleiner)
- Lambda Cold Start: 2,4 s → 650 ms (73 % schneller)
Produktions-Monitoring, keine Labortricks.
Developer Experience
Schema
// Drizzle (TypeScript)
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
});
// Prisma (DSL)
model User {
id Int @id @default(autoincrement())
name String
}
Drizzle: natives TypeScript, IDE, Generics, Conditional Types.
Prisma: kompakteres Schema, bessere Lesbarkeit.
Query-Stil
// Drizzle (SQL-like)
await db
.select()
.from(users)
.leftJoin(posts, eq(users.id, posts.authorId))
.where(gt(posts.views, 1000));
// Prisma (Chain-API)
await prisma.user.findMany({
include: {
posts: {
where: { views: { gt: 1000 } },
},
},
});
Drizzle: näher an SQL, komplexe Queries leichter.
Prisma: ohne SQL-Hintergrund einfacher, verschachtelte Queries klarer.
Funktionsvergleich
Drizzle
- Extrem leicht (7,4 kb)
- Serverless-native, schneller Cold Start
- Starke SQL-Kontrolle
- Kein Client-Generate
- Tree-shakable
Prisma
- Reife Ökosystem (seit 2021)
- Prisma Studio, Migrate, Pulse
- Intelligentere Relationen, weniger N+1
- Einsteigerfreundlicher
- Detailliertere Laufzeitfehler
Auswahl-Empfehlung
Drizzle
✅ Serverless/Edge (Vercel, Cloudflare Workers, Deno Deploy)
✅ Performancekritisch (Echtzeit, Finanz, High-Traffic-API)
✅ Bundle-Limit (< 1 MB)
✅ SQL-erfahrenes Team
✅ Komplexe SQL-Optimierung
Prisma
✅ Wenig SQL im Team
✅ DX und Toolchain wichtig
✅ Prisma Studio gewünscht
✅ Komplexe Relationen und Modellierung
✅ Kein Serverless, Bundle unkritisch
Persönliche Empfehlung
- Side Project / Startup: Drizzle (Performance, Kosten)
- Enterprise / Team: SQL stark → Drizzle; schwach → Prisma
- Serverless-First: klar Drizzle
- Klassischer Server: beides; Prisma-Toolchain reifer
Hybrid: performancekritische Module Drizzle, Admin Prisma – parallel möglich.
Migration und Best Practices
Von Prisma zu Drizzle
Progressiv starten.
Schritt 1: Schema
// Prisma
model User {
id Int @id @default(autoincrement())
name String
email String @unique
posts Post[]
createdAt DateTime @default(now())
}
// Drizzle
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
createdAt: timestamp('created_at').defaultNow(),
});
Schritt 2: Queries
// 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));
Schritt 3: Parallel betreiben
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 } } } },
},
});
Schrittweise ersetzen.
Drizzle Best Practices
1. Connection Pool (Serverless)
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. Prepared Statements
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. Transaktionen
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. Typen exportieren
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. Fehlerbehandlung
try {
await db.insert(users).values({
name: 'John',
email: '[email protected]',
});
} catch (error) {
if (error.code === '23505') {
console.error('E-Mail existiert bereits');
} else {
console.error('Datenbankfehler', error);
}
}
Fazit
Drizzle ORM versteckt SQL nicht – es umarmt SQL. 7,4 kb, null Runtime-Deps, nahezu native SQL-Performance: Leichtgewicht ist kein Kompromiss, sondern oft die bessere Wahl.
Kein vollständiger Prisma-Ersatz – Prisma hat reifere Tools und besseren Einsteigerweg. Aber bei Serverless, Performance- und Bundle-Druck, komplexem SQL und SQL-erfahrenem Team: Drizzle passt oft besser.
Unsere Zahlen: Cold Start 73 % schneller, Bundle 78 % kleiner, erste Anfrage 3 s → 700 ms. Kein Mikro-Tuning – ein Qualitätssprung.
Prisma-Cold-Start- oder Bundle-Frust? Drizzle testen – mit SQL in ~10 Minuten startklar.
Links:
- Drizzle ORM Official Documentation
- Drizzle GitHub Repository
- Next.js + Drizzle Official Tutorial
- Drizzle vs. Prisma Official Comparison
Probieren Sie es – vielleicht kommen Sie, wie ich, nicht mehr zurück.
Next.js + Drizzle ORM: Vollständiges Setup und Migrationsleitfaden
Drizzle ORM von null: Umgebung, Schema, DB-Verbindung, Queries und schrittweise Migration von Prisma
Estimated time: PT2H
-
1
Step 1: Schritt 1: Umgebung und Abhängigkeiten
Next.js-Projekt: -
2
Step 2: Schritt 2: Schema definieren
db/schema.ts: -
3
Step 3: Schritt 3: Verbindung und Drizzle Kit
db/index.ts: -
4
Step 4: Schritt 4: SQL-like API
Basis-CRUD: -
5
Step 5: Schritt 5: Server Actions
app/actions.ts: -
6
Step 6: {user.name}
{user.email} -
7
Step 7: Schritt 6: Migration von Prisma (optional)
Schema:
FAQ
Was unterscheidet Drizzle ORM von Prisma? Wann sollte man Drizzle wählen?
Performance:
• Drizzle: 7,4 kb, Cold Start 600 ms, null Runtime-Abhängigkeiten
• Prisma v5: 14 MB, Cold Start 2,5 s, Rust-Binary nötig
• Prisma v7: 1 MB, Cold Start 1,5 s – optimiert, aber weiterhin langsamer als Drizzle
Developer Experience:
• Drizzle: SQL-like API, SQL-Kenntnisse reichen, kein Client-Generate nötig
• Prisma: eigene DSL, Lernaufwand, prisma generate erforderlich
Drizzle wählen:
✅ Serverless/Edge (Vercel, Cloudflare Workers, Deno Deploy)
✅ Performancekritisch (Echtzeit, Finanzsysteme, High-Traffic-APIs)
✅ Bundle-Limit (< 1 MB)
✅ Team mit SQL-Basis, direkte Query-Kontrolle
✅ Projekte mit komplexen SQL-Optimierungen
Prisma wählen:
✅ Team ohne SQL-Erfahrung, schneller Einstieg
✅ Fokus auf DX und vollständige Toolchain
✅ Visuelles DB-Management (Prisma Studio)
✅ Komplexe Relationen und Datenmodellierung
✅ Kein Serverless, Bundle-Größe unkritisch
Was bedeutet die SQL-like API von Drizzle ORM konkret?
Beispielvergleich:
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))
```
Kernmerkmale:
• Code-Struktur fast identisch mit SQL
• Wer SQL kann, versteht die API sofort
• Lernkosten nahe null (bei SQL-Kenntnissen)
• Volle Typ-Inferenz, IntelliSense-Autovervollständigung
• Fehler schon zur Compile-Zeit
Vergleich Prisma DSL:
```typescript
// Prisma: neue Query-Syntax lernen
await prisma.user.findMany({
include: {
posts: {
where: { views: { gt: 1000 } },
},
},
});
```
Drizzle bleibt näher an nativem SQL – komplexe Queries lassen sich leichter ausdrücken.
Wie groß ist Drizzles Performance-Vorteil in Serverless-Umgebungen?
Performance:
• Erste Anfrage: 3 s → 700 ms (76 % schneller)
• Produktions-Bundle: 18 MB → 4 MB (78 % kleiner)
• Lambda Cold Start: 2,4 s → 650 ms (73 % schneller)
Ursachen:
1. Bundle-Größe:
• Drizzle-Kern nur 7,4 kb (min+gzip)
• Prisma v5 Client bis 14 MB
• Cloudflare Workers u. a. mit 1-MB-Limit – Prisma scheitert dort
2. Cold Start:
• Prisma parst beim Start große DMMF-Strings (Data Model Meta Format)
• Mittlere Schemas: über 6 Mio. Zeichen
• Jeder Cold Start erneut – daher langsam
• Drizzle: keine Runtime-Abstraktion, direkte SQL-Übersetzung
3. Speicher:
• Drizzle: ~5 MB
• Prisma v5: ~80 MB
• Prisma v7: ~30 MB (geschätzt)
Monitoring-Daten aus Produktion, keine Labortricks.
Wie migriert man von Prisma zu Drizzle? Ist das komplex?
Schritt 1: Schema-Konvertierung
Prisma Schema → Drizzle Schema:
• model → pgTable
• Int → serial/integer, String → text, DateTime → timestamp
• Relationen: Prisma-Syntax → relations()
Schritt 2: Queries umschreiben
• findUnique/findMany → select().from().where()
• include → leftJoin/innerJoin
• create → insert().values()
• update → update().set().where()
Schritt 3: Schrittweise ersetzen
Prisma und Drizzle parallel:
```typescript
// Performancekritisch: Drizzle
import { db } from '@/db/drizzle';
const latestPosts = await db
.select()
.from(posts)
.orderBy(desc(posts.createdAt))
.limit(50);
// Komplexe Relationen vorerst Prisma
import { prisma } from '@/db/prisma';
const userWithRelations = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: { include: { comments: { include: { author: true } } } },
},
});
```
Schrittweise ersetzen, Risiko senken. Hauptsächlich Syntax-Umstellung.
Welche Datenbanken und Umgebungen unterstützt Drizzle ORM?
• PostgreSQL (Neon Serverless empfohlen)
• MySQL
• SQLite (inkl. Turso, SQLite on the Edge)
• SQL Server
Serverless-Umgebungen:
• Vercel Edge Functions
• Cloudflare Workers
• AWS Lambda
• Deno Deploy
• Bun
Native Serverless-Treiber:
• Neon Serverless (PostgreSQL)
• PlanetScale (MySQL)
• Turso (SQLite on the Edge)
• Supabase (PostgreSQL)
Unser Stack: Neon + Drizzle auf Vercel Edge – Cold Start von 2,5 s auf 700 ms.
Vorteile:
• Alle gängigen Serverless-Umgebungen
• Native Serverless-DB-Treiber
• Null Runtime-Abhängigkeiten – läuft überall mit JavaScript
Wie ist Drizzles Typsicherheit im Vergleich zu Prisma?
Typ-Inferenz:
Drizzle (automatisch):
```typescript
// Rückgabetyp automatisch
const users = await db.select().from(users);
// Typ: { id: number; name: string; email: string; createdAt: Date }[]
// Felder wählen – Typ passt sich an
const result = await db
.select({
id: users.id,
name: users.name,
})
.from(users);
// Typ: { id: number; name: string }[]
// Compile-Fehler
await db.select().from(users).where(eq(users.id, '1'));
// ❌ TypeScript: string nicht zu number zuweisbar
```
Kernmerkmale:
• Kein Client-Generate, TypeScript inferiert direkt
• IntelliSense für Felder, Funktionen, Operatoren
• Fehler zur Compile-Zeit, nicht erst zur Laufzeit
• Schnellere Typ-Checks (einfachere Inferenz)
Prisma:
• prisma generate nötig
• Große Projekte: langsamere TS-Kompilierung
• Drizzle: schnellere Builds
Typen fürs Frontend:
```typescript
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;
```
Ist Drizzle ORM für Einsteiger geeignet? Wie steil ist die Lernkurve?
Einstieg:
• SQL-Kenntnisse: ~10 Minuten
• Ohne SQL: zuerst SQL-Grundlagen
Warum geringe Lernkosten:
• SQL-like API, Struktur wie SQL
• Keine neue DSL wie bei Prisma
• Volle Typ-Hinweise, IntelliSense
• TypeScript-Compiler als beste Dokumentation
Beispiele:
```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))
```
Wer SQL kann, braucht kaum Docs.
Prisma:
• Eigene DSL lernen
• Freundlicher ohne SQL-Hintergrund
• Mit SQL: Drizzle oft intuitiver
Empfehlung:
• Starkes SQL-Team: Drizzle
• Schwaches SQL: Prisma – oder SQL lernen, dann Drizzle
11 Min. Lesezeit · Veröffentlicht am: 20. Dez. 2025 · Aktualisiert am: 14. Juli 2026
Next.js Komplettleitfaden
Wenn du über die Suche hier gelandet bist, kommst du am schnellsten weiter, indem du zum vorherigen oder nächsten Beitrag dieser Serie springst.
Vorheriger
SWR – vollständiger Leitfaden: Cache-Strategien und optimistische Updates in der Praxis
Lernen Sie die Kernkonzepte und Cache-Strategien von SWR kennen und vereinfachen Sie bis zu 90 % Ihres Datenabruf-Codes mit einem Hook. Inklusive Praxisbeispielen für optimistische Updates, Vergleich mit React Query und Best Practices für die Next.js-Integration.
Teil 50 von 51
Nächster
Dies ist bisher der neueste Beitrag dieser Serie.
Ähnliche Beiträge
Next.js App Router Einstieg: Kernkonzepte und Grundlagen im Überblick

Next.js App Router Einstieg: Kernkonzepte und Grundlagen im Überblick
Next.js 15 in der Praxis: Wie ich an einem Wochenende ein produktionsreifes Blog-System aufgebaut habe


Kommentare
Melde dich mit GitHub an, um einen Kommentar zu hinterlassen