Startseite / Artikel

Einführung von Prisma 7 mit PostgreSQL in einem TypeScript-Node.js-Projekt

Beheben Sie die häufigen Prisma 7-Einrichtungsfehler in TypeScript – von String- oder undefined-URLs über Probleme mit rootDir bis hin zur Anbindung an PostgreSQL mittels des pg-Driver-Adapters.

Verlag: REACTAPP.TOP7 Min. Lesezeit1666 Wörter

Quellen: I Wasted 4 Hours Setting Up Prisma — Here’s How You Should Set Up Prisma v7

Das Nachvollziehen des Prisma Quickstarts in einem einfachen TypeScript Node.js-Projekt endet oft mit einer Flut an Kompilierfehlern, noch bevor eine einzige Abfrage ausgeführt werden kann. Die Probleme liegen nicht in den Modellen, sondern darin, wie der TypeScript-Kompilator, Prismas neues Konfigurationsfile sowie der generierte Client mit einer herkömmlichen src/dist-Struktur interagieren. Diese Anleitung erläutert die drei Fehler, auf die man am ehesten stößt, warum sie auftreten, sowie eine schrittweise Einrichtung mit PostgreSQL, bei der sauber kompiliert werden kann. Prisma 7 hat mehrere Standardwerte geändert, daher sollten Sie die aktuelle Prisma-Dokumentation prüfen, um festzustellen, ob seit der Erstellung dieser Anleitung etwas verschoben wurde.

Die drei Fehler, die eine neue Einrichtung vereiteln

Eine Verbindungs-URL, die als Zeichenkette oder undefined eingegeben wird

In prisma.config.ts wird die Datenbank-URL in der Regel mit process.env.DATABASE_URL abgerufen. TypeScript klassifiziert jede Umgebungsvariable als string | undefined, da nichts garantiert, dass sie zur Laufzeit gesetzt ist. Die Konfiguration erwartet jedoch einen einfachen string, weshalb der Compiler die Zuweisung ablehnt.

prisma.config.ts außerhalb des Wurzelverzeichnisses

In einem typischen TypeScript-Projekt wird rootDir auf src und outDir auf dist gesetzt. Prisma erstellt prisma.config.ts im Projektverzeichnis, und standardmäßig berücksichtigt der Compiler alle gefundenen .ts-Dateien. Anschließend meldet er, dass eine Datei außerhalb von rootDir zum Programm gehört. Das Verschieben der Konfiguration in src würde den Fehler beseitigen, doch das ist die falsche Lösung: src dient dem Anwendungscode wie Routen, Controllern und Datenzugriffsmethoden, nicht der Konfiguration von Tools.

Ein generierter Client außerhalb des Root-Verzeichnisses

Das Gleiche passiert mit dem generierten Client. Wenn Prisma diesen in generated/prisma am Projektroot speichert, findet der Compiler erneut TypeScript-Dateien außerhalb von rootDir. Die Verlegung des generierten Codes in src ist ebenfalls eine schlechte Entscheidung, da es sich um Ausgabe des Builds von prisma generate handelt und nicht um Quellcode, den man selbst pflegt.

Wenn diese Probleme ungelöst bleiben, verhindern sie den Start des Projekts. Ein ebenso ärgerlicher Nebeneffekt ist, dass der kompilierte JavaScript-Code für prisma.config.ts außerhalb von dist landen kann und so den Repository verunreinigt. Das Einzelne Beheben von Fehlern führt oft zu neuen Problemen, weshalb es sinnvoll ist, die gesamte Konfiguration zu korrigieren.

Schritt 1: Projekt erstellen und Abhängigkeiten installieren

Fangen Sie mit einem leeren TypeScript-Projekt an. Installieren Sie den Compiler, tsx zur direkten Ausführung von TypeScript sowie die Typdefinitionen von Node, und erzeugen Sie anschließend eine tsconfig.json:

npm init
npm install typescript tsx @types/node --save-dev
npx tsc --init

Danach installieren Sie Prisma. Die CLI sowie die pg-Typdefinitionen sind Entwicklungskomponenten; der Client, der PostgreSQL-Driver-Adapter, der pg-Driver und dotenv sind Laufzeitkomponenten:

npm install prisma @types/pg --save-dev
npm install @prisma/client @prisma/adapter-pg pg dotenv

Das Paket @prisma/adapter-pg ist hier wichtig. In Prisma 7 kommuniziert der Client mit der Datenbank über einen JavaScript-Driver-Adapter, weshalb Ihnen eine konfigurierte pg-Verbindung übergeben wird, anstatt sich allein auf eine URL im Schema zu verlassen.

Schritt 2: Konfigurieren von ES-Modulen und der Compilerstruktur

Markieren Sie das Paket als ES-Modul in package.json:

{
  "type": "module"
}

Legen Sie anschließend die Quell- und Ausgabeverzeichnisse in tsconfig.json fest und erstellen Sie das Verzeichnis src:

"rootDir": "./src",
"outDir": "./dist",

Schritt 3: Prisma initialisieren

Führen Sie die CLI einmal aus (dadurch werden lediglich die verfügbaren Befehle angezeigt und bestätigt, dass die Installation funktioniert):

npx prisma

Initialisieren Sie danach Prisma für PostgreSQL:

npx prisma init --datasource-provider postgresql --output ../generated/prisma

Dadurch entstehen prisma.config.ts, ein prisma-Verzeichnis mit schema.prisma sowie eine .env-Datei für die Datenbank-URL. Der Flag --output legt fest, wo der Client generiert werden soll; Schritt 4 befasst sich erneut mit dieser Auswahl. Genau nach diesem Schritt treten die oben beschriebenen Fehler auf.

Schritt 4: Konfiguration korrigieren

Drei gezielte Änderungen beheben alle drei Fehler.

Die URL mit Prismas env-Hilfsfunktion lesen

Ersetzen Sie den Inhalt von prisma.config.ts durch den folgenden Text. Diese Datei ist in TypeScript geschrieben, obwohl der Auszug anders beschriftet ist.

import "dotenv/config";
import type { PrismaConfig } from "prisma";
import { env } from "prisma/config";

export default {
  schema: "prisma/schema.prisma",
  migrations: {
    path: "prisma/migrations",
    seed: "tsx prisma/seed.ts",
  },
  datasource: {
    url: env("DATABASE_URL"),
  },
} satisfies PrismaConfig;

Was zu beachten ist:

  • import „dotenv/config“ lädt .env bereits vor dem Lesen durch andere Teile des Codes. Prisma 7 lädt es in dieser Konfiguration nicht mehr automatisch für Sie.
  • env(„DATABASE_URL“) aus prisma/config gibt einen String zurück und wirft bei Fehlen der Variable eine deutliche Fehlermeldung aus, wodurch das Problem mit String | undefined beseitigt wird.
  • satisfies PrismaConfig überprüft das Objekt auf Typfehler, ohne dessen Typ zu erweitern.
  • Die Konfiguration gibt außerdem an, wo die Schema-Dateien und Migrationsdateien liegen sowie welcher Befehl die Datenbank initialisiert.

Beschränken Sie, was der Compiler einbezieht

Fügen Sie einen include-Eintrag am Ende von tsconfig.json hinzu:

"include": ["src"],

Dies weist den Compiler an, nur die Dateien unter src zu kompilieren. Die Prisma CLI liest weiterhin prisma.config.ts eigenständig, aber tsc behandelt es nicht mehr als Teil Ihres Programms – dadurch verschwindet der Fehler bezüglich rootDir und es werden keine unerwünschten JavaScript-Dateien außerhalb von dist erzeugt.

Erstellen Sie den Client in node_modules

Zum Schluss bearbeiten Sie schema.prisma, damit der Generator keinen benutzerdefinierten Ausgabepfad hat:

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"

Fehlt ein output, schreibt der Generator von prisma-client-js den Client in node_modules, sodass nichts im Projektverzeichnis generiert wird und der Fehler bezüglich des rootDir verschwindet. Der Codeausschnitt endet nach dem provider für die Datenquelle; schließen Sie den Block mit einer Klammer. In Prisma 7 befindet sich die Verbindungs-URL in prisma.config.ts, nicht im Schema.

Bedenken Sie, dass es sich um einen Kompromiss handelt. Prismas neuerer prisma-client-Generator ist um ein explizites Ausgabeverzeichnis konzipiert, während prisma-client-js der ältere Generator ist. Wenn Sie den neueren verwenden, platzieren Sie seine Ausgabe außerhalb von src und ausschließen Sie sie über include vor tsc, wie oben beschrieben.

Schritt 5: Datenbank-URL hinzufügen und migrieren

Platzieren Sie Ihre Verbindungszeichenkette in .env. Der untenstehende Wert ist ein Platzhalter; verwenden Sie Ihre eigene Datenbank und übergeben Sie niemals echte Werte:

DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"

Definieren Sie Ihre Modelle in schema.prisma, erstellen Sie anschließend die erste Migration und wenden Sie sie an:

npx prisma migrate dev --name init

Schritt 6: Client generieren

Erstellen Sie den typisierten Client aus dem Schema:

npx prisma generate

Führen Sie dies erneut aus, sobald sich das Schema ändert, damit die Typen mit Ihren Modellen synchron bleiben.

Schritt 7: Eine gemeinsame Prisma-Instanz erstellen

Erstellen Sie src/lib/prisma.ts, um einen Client für die gesamte Anwendung zu speichern. Dieser erstellt einen PostgreSQL-Adapter aus der Verbindungszeichenkette und gibt ihn an PrismaClient weiter. Auch dieser Code ist in TypeScript geschrieben:

import "dotenv/config";
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "../../node_modules/@prisma/client/index.js";

const connectionString = `${process.env.DATABASE_URL}`;

const adapter = new PrismaPg({ connectionString });
const prisma = new PrismaClient({ adapter });

export default prisma;

Der Client wird über einen expliziten relativen Pfad in node_modules importiert:

import { PrismaClient } from "../../node_modules/@prisma/client/index.js";

Der Pfad funktioniert, weil der Client in Schritt 4 in node_modules erzeugt wurde. In den meisten Konfigurationen führt der einfache Spezifikator @prisma/client zum selben Paket, daher sollten Sie zunächst damit versuchen; wenden Sie den expliziten Pfad nur an, wenn Ihre Module-Resolutionseinstellungen dies erfordern.

Eine Fallgrube in diesem Beispiel: Das Einbetten von process.env.DATABASE_URL in eine Template-String verwandelt einen fehlenden Wert in den Text "undefined", was später zu verwirrenden Verbindungsfehlern führt. Eine kurze Überprüfung, die bei Abwesenheit der Variable einen Fehler auslöst, macht Fehlschläge deutlich sichtbar.

Importieren Sie nun diese Instanz überall dort, wo Sie auf die Datenbank zugreifen müssen – beispielsweise in Controllern oder Services – und führen Sie Ihre CRUD-Anfragen darüber aus. Durch die Verwendung eines gemeinsamen Clients wird verhindert, dass pro Datei ein neuer Connection Pool eröffnet wird.

Wichtige Erkenntnisse

  • Die meisten Einrichtungsfehler von Prisma 7 in TypeScript stammen von den Regeln für rootDir des Compilers und nicht von Prisma selbst.
  • Verwenden Sie env() aus prisma/config zusammen mit dotenv/config, um eine korrekt typisierte, explizit geladene Datenbank-URL zu erhalten.
  • Beschränken Sie tsc mit "include": ["src"], damit Tooling-Dateien und generierter Code nicht in die Build-Prozesse einfließen.
  • Lassen Sie generierte Clients außerhalb von src – entweder in node_modules oder in einem ausgeschlossenen Ausgabeverzeichnis.
  • Erstellen Sie eine gemeinsame PrismaClient-Instanz mit dem PrismaPg-Adapter und überprüfen Sie die Verbindungszeichenkette beim Start.

Falls Sie Next.js anstelle eines einfachen Node.js-Diensts verwenden, behandelt unser Leitfaden zu der Einrichtung von Prisma 7 in einem Next.js 16 TypeScript-Projekt die für dieses Framework spezifischen Details.