Drizzle gegen Prisma: Die Wahl eines TypeScript ORM ohne Hype
Vergleichen Sie Drizzle und Prisma hinsichtlich Schema-Design, Abfragesyntax, verschachtelter Schreibvorgänge, Migrationsprozessen, Transaktionen und Leistung, und erhalten Sie Ratschläge, welches Tool für welches Team am besten geeignet ist.
Quellen: Drizzle vs Prisma: Choosing the Right TypeScript ORM in 2026 (Deep Dive)
Drizzle ORM und Prisma sind die beiden Namen, die am häufigsten auftauchen, wenn man für ein TypeScript-Projekt ein ORM auswählt. Sie lösen dasselbe Problem – nämlich den Zugriff auf Datenbanken in typisierten Code umzuwandeln – doch sie gehen von entgegengesetzten Ansätzen aus, was die Nähe zum SQL betrifft. Keine der beiden Optionen ist falsch. Wenn Ihr Team bereits eines davon gut kennt, nutzen Sie es weiter und konzentrieren Sie sich auf das Produkt. Der Vergleich ist wichtiger, wenn Sie etwas Neues starten oder einer Kollegenschaft eine bestehende Einrichtung erklären müssen.
Die beiden Tools
Drizzle tauchte 2022 auf und verbreitete sich schnell unter Entwicklern, die Kontrolle ohne zusätzliches Gewicht wünschen. Es ist typisiertes TypeScript in der ersten Linie: Tabellen, Beziehungen und Abfragen werden alle in TypeScript deklariert. Eine angemessene Beschreibung ist eine schlanke, typisierte Schicht über SQL. Typen werden nativ abgeleitet, roher SQL bleibt typsicher, und das Design eignet sich für leistungsintensiven Code. Unterstützt werden PostgreSQL, MySQL, SQLite und SQL Server.
Prisma kam bereits 2018 auf den Markt und baute seinen Ruf auf der Entwicklererfahrung, Produktivität sowie den verfügbaren Tools auf. Das Datenmodell befindet sich in einer .prisma-Datei, die in der Prisma Schema Language (PSL) geschrieben ist, und prisma generate wandelt es in einen vollständig typisierten Client mit einer hochrangigen API um. Die Beziehungen zwischen den Daten werden automatisch gehandhabt, und das Ökosystem ist größer und reifer – es umfasst unter anderem Prisma Studio, einen visuellen Browser und Editor für Ihre Daten. Unterstützte Datenbanken sind unter anderem PostgreSQL, MySQL, SQLite und MongoDB.
Schema definieren
Hier unterscheiden sich die Philosophien am deutlichsten, und die gewählte Methode prägt die tägliche Arbeit sowie die Typsicherheit.
Drizzle: Code zuerst
Ein Drizzle-Schema besteht aus reinem TypeScript. Tabellen, Spalten und Beziehungen befinden sich in derselben Sprache wie die Anwendung, sodass es keinen Generierungsschritt gibt und Änderungen sofort im Editor sichtbar werden.
import { pgTable, serial, varchar, text, integer, timestamp } from "drizzle-orm/pg-core";
// Authors table
export const authors = pgTable("authors", {
id: serial("id").primaryKey(),
name: varchar("name", { length: 100 }).notNull(),
bio: text("bio"),
});
// Books table referencing Authors
export const books = pgTable("books", {
id: serial("id").primaryKey(),
title: varchar("title", { length: 150 }).notNull(),
summary: text("summary"),
authorId: integer("author_id")
.notNull()
.references(() => authors.id),
publishedAt: timestamp("published_at").defaultNow(),
});
Weil die Typen automatisch abgeleitet werden, hat das Ergebnis einer Abfrage eine bekannte Struktur – ohne zusätzliche Schema-Datei. Dadurch werden Laufzeitüberraschungen vermieden.
Prisma: Schema zuerst
Prisma speichert das Modell in einer separaten .prisma-Datei:
model Author {
id Int @id @default(autoincrement())
name String
bio String?
books Book[]
}
model Book {
id Int @id @default(autoincrement())
title String
summary String?
publishedAt DateTime @default(now())
authorId Int
author Author @relation(fields: [authorId], references: [id])
}
Das Schema ist sauber vom Anwendungscode getrennt. Nach jeder Änderung erstellt prisma generate den Client erneut, sodass die Typen übereinstimmen. Für Personen mit geringen SQL-Kenntnissen ist diese Abstraktion freundlicher, da man mit einem generierten, hochrangigen Client arbeitet anstelle von SQL-ähnlicher Logik. Der Nachteil ist jedoch eine weitere Schicht zwischen dem Code und der Datenbank.
Abfragen schreiben
Sowohl Ansätze bieten typgeprüfte Abfragen, doch sie fühlen sich beim Schreiben unterschiedlich an.
Drizzle
Der Abfragebauer ist absichtlich klein und vorhersehbar und liest sich wie SQL. Wenn man sich mit JOINs und WHERE-Klauseln auskennt, wirkt er natürlich, und das, was man schreibt, entspricht weitgehend dem, was in der Datenbank ausgeführt wird. Dieses Beispiel verknüpft Bücher mit Autoren und filtert sowie sortiert das Ergebnis:
const results = await db
.select({
bookId: books.id,
title: books.title,
publishedAt: books.publishedAt,
authorName: authors.name,
})
.from(books)
.leftJoin(authors, eq(books.authorId, authors.id))
.where(eq(authors.id, authorId))
.orderBy(books.publishedAt);
Man erhält eine feine Steuerung sowie hochvorhersehbares SQL. Der deutliche Unterschied im Vergleich zu Prisma zeigt sich beim Erstellen von verknüpften Zeilen. Drizzle verfügt nicht über verschachtelte Schreibvorgänge, wodurch jede relationale Eingabe manuell abgewickelt wird – in der Regel innerhalb einer Transaktion, damit alle Elemente konsistent bleiben:
const result = await db.transaction(async (tx) => {
const [newAuthor] = await tx.insert(authors).values({
name: "Alice",
bio: "Fantasy author",
}).returning({ id: authors.id });
const [newBook] = await tx.insert(books).values({
title: "The Dream Forest",
authorId: newAuthor.id,
}).returning();
return { newAuthor, newBook };
});
Volle Transparenz ist der Vorteil. Mehr Standardcode ist der Nachteil.
Prisma
Prisma wählt den entgegengesetzten Ansatz. Man ruft Methoden auf einem automatisch generierten Client auf, während die Datenbank weiterhin über objektorientierte Methoden verfügt. Die gleiche Abfrage sieht dann so aus:
const results = await prisma.book.findMany({
where: { authorId },
select: {
id: true,
title: true,
publishedAt: true,
author: {
select: { name: true },
},
},
orderBy: { publishedAt: "asc" },
});
Man muss hier nicht in SQL denken, was viel zur Beliebtheit von Prisma beiträgt. Es zeichnet sich auch bei der Erstellung von verknüpften Daten aus, da eingebettete Schreibvorgänge unterstützt werden. Ein Buch und sein Autor können in einem einzigen Aufruf erstellt werden:
const newBook = await prisma.book.create({
data: {
title: "The Dream Forest",
summary: "A surreal adventure.",
author: {
create: {
name: "Alice",
bio: "Fantasy author",
},
},
},
});
Es müssen keine Fremdschlüssel manuell verknüpft werden. Was Sie dabei aufgeben, ist die Sichtbarkeit, da der tatsächlich ausgeführte SQL vor Ihnen verborgen bleibt, wodurch Sie weniger Kontrolle haben als mit Drizzle.
Migrationen
Die Änderung des Schemas im Laufe der Zeit ist in jedem echten Projekt wichtig, und beide Tools bewältigen dies gut.
Drizzle
Da das Schema in TypeScript vorliegt, ist es die Quelle der Wahrheit, und die CLI (drizzle-kit) erstellt Migrationen auf der Grundlage von Unterschieden in Ihren Definitionen. In einem auf Migrationen basierenden Workflow beginnen Sie damit, Folgendes zu generieren:
npx drizzle-kit generate
Dies vergleicht den aktuellen Zustand mit Ihrem TypeScript-Schema und erstellt eine Migrationsdatei mit den SQL-Änderungen, die Sie vor der Verwendung manuell bearbeiten können. Die Anwendung erfolgt über einen separaten Befehl:
npx drizzle-kit migrate
Für das schnelle Prototyping gibt es auch einen Shortcut:
npx drizzle-kit push
Es überträgt das TypeScript-Schema direkt in die Datenbank, ohne eine Migration-Datei zu erstellen. Das ist zu Beginn schnell und praktisch, doch ohne Migrationshistorie eignet es sich nicht für die Produktion.
Prisma
Bei Prisma ist die .prisma-Datei die Quelle der Wahrheit, und das Tool erstellt den SQL-Code für jede Änderung. Die Anwendung von kommitierten Migrationsen in einer Datenbank erfolgt mithilfe von:
npx prisma migrate deploy
Während der Entwicklung ist prisma migrate dev der Befehl, der einen neuen Migrationsordner mit SQL-Skripten erstellt, diese anwendet und die Historietabelle aktualisiert. Dadurch entsteht ein übersichtlicher, größtenteils automatisierter Arbeitsablauf.
Auch für das Prototyping gibt es einen Shortcut:
npx prisma db push
Es aktualisiert die Datenbank direkt, ähnlich wie Drizzle’s Push, ohne Migrationsdateien – daher ist es nur für den Nicht-Produktivgebrauch geeignet.
Transaktionen
Sowohl Lösungen unterstützen Transaktionen, wobei es geringe stilistische Unterschiede gibt.
Drizzle verwendet db.transaction zusammen mit einem Callback. Jede Abfrage innerhalb dieses Blocks ist entweder erfolgreich oder fehlschlägt gemeinsam, und da man sich in der Nähe von SQL aufhält, kann man genau steuern, was im Block geschieht:
await db.transaction(async (tx) => {
const newAuthor = await tx.insert(authors).values({
name: "Alice Walker",
bio: "Pulitzer Prize-winning author",
}).returning();
await tx.insert(books).values({
title: "Journey to the Mountains",
summary: "A story about adventure and discovery.",
authorId: newAuthor[0].id,
});
});
Prisma bietet prisma.$transaction an, der entweder ein Array von Abfragen oder einen asynchronen Callback akzeptiert. Commit und Rollback erfolgen automatisch:
await prisma.$transaction(async (tx) => {
const newAuthor = await tx.author.create({
data: {
name: "Alice Walker",
bio: "Pulitzer Prize-winning author",
},
});
await tx.book.create({
data: {
title: "Journey to the Mountains",
summary: "A story about adventure and discovery.",
authorId: newAuthor.id,
},
});
});
Leistung
Bei der Leistung spielen die zugrundeliegenden Philosophien die größte Rolle.
Drizzle ist leichtgewichtig, und seine Abfragen entsprechen fast direkt den Datenbankoperationen, wodurch es nur sehr geringe Abstraktionskosten gibt. Das ist nützlich für komplexe Abfragen, Massenoperationen und hochperformanten Code. Durch die volle Kontrolle über Joins, Transaktionen und die Struktur der Abfragen ist eine Optimierung für Geschwindigkeit einfacher – vorausgesetzt, man versteht SQL und das Datenbankdesign.
Der von Prisma generierte Client versteckt SQL hinter einer hochwertigen API. Dadurch entstehen geringfügige Leistungseinbußen, doch in den meisten gewöhnlichen Anwendungen ist der Unterschied vernachlässigbar. Beziehungen, verschachtelte Abfragen sowie typisierte Ergebnisse sind kostenlos verfügbar, was die Entwicklung beschleunigt. Die Bequemlichkeit kann jedoch manchmal dazu führen, dass der generierte SQL weniger optimiert ist als eine sorgfältig manuell geschriebene Abfrage.
Wahl zwischen ihnen
Sowohl Tools sind moderne ORMs, die TypeScript unterstützen und Typsicherheit, Migrationsfunktionen, Beziehungen sowie Transaktionen bieten – die Entscheidung hängt also von den Prioritäten ab.
Wählen Sie Drizzle, wenn Sie sich SQL näher halten möchten, die Kontrolle über Abfragen und Migrationsprozesse behalten wollen und eine vorhersehbare Leistung bei großen oder komplexen Arbeitslasten benötigen. TypeScript dient als einzige Quelle der Wahrheit, und nichts bleibt verborgen.
Wählen Sie Prisma, wenn das Team schnell vorankommen möchte, sich auf Funktionen konzentrieren will und bei Migrationsprozessen, Abfragen sowie Beziehungen auf Automatisierung setzt. Das schema-basierte Modell sowie der generierte Client liefern eine saubere, hochlevelige API, die auch Anfängern zugänglich ist.
Kurz gesagt:
- Schema: TypeScript-Code (Drizzle) gegenüber einer
.prisma-Datei zusammen mit der Generierung (Prisma). - Abfragen: sql-ähnlich und explizit gegenüber objektorientiertem und abstraktem Stil.
- Verwaltung von verschachtelten Schreibvorgängen: manuell in Drizzle, integriert in Prisma.