Next.js-Entwickler in Dresden

Next.js mit PostgreSQL: wo Abfragen laufen, Prisma oder Drizzle, Verbindungen auf Node-Server und Serverless, Migrationen im Deployment, Backups und was die sächsische Datenschutzaufsicht 2026 meldet.

Next.js-Entwickler

Mein Platz in der WordPress-Community

  • Mein wordpress.org-Konto besteht seit 2006.
  • Ich habe zum WordPress-Core in den Versionen 7.0 und 7.1 beigetragen.
  • Ich betreue 30 Plugins auf wordpress.org.
  • Ich organisiere WordCamps und trete dort als Speaker auf.
  • Ich war bei jedem WordCamp Europe von 2017 bis 2026 dabei.
  • Lokales WordPress-Meetup: WordPress Meetup Dresden

Mein WordPress.org-Profil

#Next.js mit PostgreSQL: wenn die Anwendung Daten speichert

Sobald eine Next.js-Anwendung mehr ist als eine Broschüre, braucht sie eine Datenbank: für Anfragen und Aufträge, Kundenkonten, Produktdaten oder die Protokolle eines Portals. Für relationale Daten ist PostgreSQL meine Standardwahl. Diese Seite beschreibt, wie ich Next.js damit verbinde und welche Entscheidungen später Ärger machen, wenn sie am Anfang offen bleiben: wo die Abfragen laufen, welche Bibliothek sie ausführt, wie viele Verbindungen die Anwendung öffnen darf, wie Schemaänderungen live gehen und was ein Backup wirklich wiederherstellt.

Stand November 2026 ist Next.js 16.4.6 die aktuelle Version laut npm. Die Anmeldung beschreibe ich auf der Seite für Wiesbaden, den Betrieb auf eigenem Server auf der für Berlin, Cache und Revalidierung auf der für Augsburg. Hier geht es um die Datenbank dahinter.

#Wo Abfragen laufen: die Datenzugriffsschicht

In Server Components darf Code direkt auf eine Datenbank zugreifen. Die Anleitung Fetching Data begründet das so: Zugangsdaten und Abfragelogik landen nicht im Client-Bundle. Die Anleitung zur Datensicherheit unterscheidet drei Wege. Bestehende HTTP-Schnittstellen weiter aufrufen, eine Datenzugriffsschicht für neue Projekte, Abfragen direkt in der Komponente für Prototypen. Empfohlen wird, einen Weg zu wählen und nicht zu mischen, damit Entwickler und Prüfer wissen, was sie erwartet.

Die Datenzugriffsschicht, kurz DAL, läuft nur auf dem Server, prüft Berechtigungen und gibt kleine Datenobjekte zurück. Der Grund für den Prototypen-Vermerk bei direkten Abfragen: Reicht eine Server Component einen ganzen Datensatz an eine Client Component weiter, gehen alle Felder an den Browser. Ich baue deshalb jedes neue Projekt mit einer DAL. Das Beispiel nutzt Drizzle und pg; es ist gegen drizzle-orm 0.45.4 typgeprüft:

// lib/db.ts
import 'server-only'
import { Pool } from 'pg'
import { drizzle } from 'drizzle-orm/node-postgres'
import * as schema from './schema'

const global_ = globalThis as unknown as { pool?: Pool }

const pool =
  global_.pool ??
  new Pool({ connectionString: process.env.DATABASE_URL, max: 5 })

if (process.env.NODE_ENV !== 'production') global_.pool = pool

export const db = drizzle({ client: pool, schema })
// lib/dal.ts
import 'server-only'
import { cache } from 'react'
import { and, desc, eq } from 'drizzle-orm'
import { db } from './db'
import { anfragen } from './schema'
import { requireKunde } from './auth'

export const offeneAnfragen = cache(async () => {
  const { kundeId } = await requireKunde()
  return db
    .select({ id: anfragen.id, betreff: anfragen.betreff, erstellt: anfragen.erstellt })
    .from(anfragen)
    .where(and(eq(anfragen.kundeId, kundeId), eq(anfragen.status, 'offen')))
    .orderBy(desc(anfragen.erstellt))
})

Drei Punkte darin sind Absicht. Das Paket server-only bricht den Build ab, falls jemand die Datei in eine Client-Komponente importiert. Die Abfrage wählt einzelne Spalten statt der ganzen Tabelle, und der Kunde kommt aus der Sitzung, nicht aus einem Parameter der Anfrage. Und cache aus React sorgt laut Next.js-Doku dafür, dass mehrere Komponenten innerhalb einer Anfrage dasselbe Ergebnis teilen; über Anfragen hinweg gilt das nicht.

Dev-Server haben eine eigene Falle. Die Prisma-Doku beschreibt, dass Next.js beim Hot Reloading Module oft neu lädt und dabei mehrere Clients entstehen, die Ressourcen verbrauchen. Ihre Lösung ist eine einzige Instanz auf einer globalen Variable, die nur außerhalb der Produktion gesetzt wird. Das Beispiel oben macht dasselbe für den pg-Pool.

#Prisma oder Drizzle

Beide sprechen PostgreSQL, beide sind TypeScript-first, und beide laufen in Server Components. Die Unterschiede, die ich im Projekt spüre, liegen woanders.

PunktPrismaDrizzle
Schemaeigene Schemadatei, daraus ein generierter ClientTypeScript-Dateien mit pgTable
Migrationenprisma migrate, angewendet mit migrate deploydrizzle-kit generate erzeugt SQL, migrate wendet es an
Verbindungseit Version 7 über Treiberadapter, Pool kommt vom TreiberTreiber Ihrer Wahl, etwa pg; die Doku listet auch Neon, Supabase und andere
Version auf npm, November 2026Tag latest: 8.0.0-rc.33; neueste 7er-Version: 7.10.1Tag latest: 0.45.4; die Einstiegsseite der Doku installiert die 1.0 als rc

Die letzte Zeile ist ein Hinweis zur Lieferkette: Bei beiden zeigt die Dokumentation auf eine neuere Version als die, die ein npm install ohne Zusatz liefert. Ich lege deshalb im Angebot schriftlich fest, auf welcher Version das Projekt startet, und prüfe vor dem Start, ob die Doku zu dieser Version passt.

Meine Faustregel: Drizzle, wenn das Team SQL liest und jede Migrationsdatei im Pull Request prüfen soll. Prisma, wenn Sie ein Schema in einer eigenen, kompakten Sprache und einen fertigen Client wollen. Wechseln lässt sich später, aber nicht kostenlos, weil Schema und Migrationsverlauf mitwandern.

#Verbindungen: Node-Server und Serverless

PostgreSQL begrenzt die gleichzeitigen Verbindungen. Laut Dokumentation steht max_connections typischerweise auf 100, und drei Plätze sind standardmäßig für Superuser reserviert. Ab da kommen nur noch Superuser hinein.

Auf einem Node-Server mit einem Prozess ist das einfach: ein Pool, im Beispiel mit höchstens fünf Verbindungen. Die Doku von node-postgres rät, wenige Pools zu halten, meist genau einen, weil unbegrenzt viele Pools den Zweck des Poolings aufheben. Bei Prisma 7 kommt die Pool-Größe vom Treiber. Die Prisma-Doku nennt für pg den Standard 10 und die Einstellung max am Adapter.

Anders bei Funktionen ohne Dauerlauf. Die Prisma-Doku beschreibt, dass dort jede Funktion ihren eigenen Client und Pool anlegt und so die Verbindungen der Datenbank ausschöpfen kann. Eine Rechnung zeigt, wie schnell das geht: Zehn Instanzen mit vollem Standardpool wollen 100 Verbindungen, und das Limit liegt bei 100 abzüglich der drei reservierten. Als Gegenmittel empfiehlt Prisma einen externen Pooler wie PgBouncer.

Der hat Bedingungen. Laut PgBouncer-Doku vergibt der Transaktionsmodus eine Serververbindung nur für die Dauer einer Transaktion. Dafür brechen einige Sitzungsfunktionen: SET, PREPARE, LISTEN und Session-Advisory-Locks gehen in diesem Modus nicht. Protokollebene Prepared Statements gehen nur, wenn max_prepared_statements größer null ist. Prisma verlangt für den Betrieb den Transaktionsmodus und weist darauf hin, dass der Migrationsbefehl eine einzelne, direkte Verbindung nutzt und nicht über den Pooler laufen soll. In Prisma 7 trägt man dafür eine eigene URL für die Befehlszeile in prisma.config.ts ein, während die Anwendung die gepoolte URL behält.

BetriebsartPool in der AnwendungWorauf ich achte
Ein Node-Serverein Pool, kleine GrößeInstanzen mal Pool bleibt unter dem Limit
Mehrere Containerein Pool je ContainerSumme über alle Container rechnen
Funktionen ohne Dauerlaufkleiner Pool je FunktionPooler vor der Datenbank, Transaktionsmodus beachten
Migrationennicht über den Poolerdirekte Verbindung für den Migrationsschritt

Kuppel der Yenidze in Dresden

Foto: Nightflyer, CC BY-SA 4.0, Wikimedia Commons.

#Migrationen im Deployment

Eine Schemaänderung ist der riskanteste Teil eines Releases, weil sie alte und neue Programmversion für eine Weile gleichzeitig trifft. Beide Bibliotheken zerlegen den Ablauf in zwei Schritte: Änderung als Datei festhalten, Datei auf der Zieldatenbank anwenden.

Bei Prisma ist der zweite Schritt prisma migrate deploy. Laut Referenz wendet er alle offenen Migrationen an und ist vor allem für Umgebungen jenseits der Entwicklung gedacht. Er prüft weder auf Abweichungen zwischen Datenbank und Schema, noch nutzt er eine Shadow-Datenbank. Die Anleitung zum Deployment zeigt ihn als Pipeline-Schritt, und die Anleitung für Vercel gibt ein Build-Skript vor: prisma generate && prisma migrate deploy && next build. Dieselbe Seite warnt vor einer Falle. Nutzt eine Vorschau-Umgebung dieselbe DATABASE_URL wie die Produktion, kann ein Pull Request mit Schemaänderung die Produktionsdatenbank verändern. Vorschau-Deployments bekommen deshalb eine eigene Datenbank.

Bei Drizzle liest drizzle-kit migrate laut Doku die SQL-Dateien, holt den Verlauf aus der Datenbank, wählt die noch nicht angewendeten und führt sie aus. generate legt pro Änderung einen Ordner mit migration.sql und snapshot.json an; generate --custom erzeugt eine leere Datei für handgeschriebenes SQL. push schreibt das Schema ohne Migrationsdateien und gilt laut Doku als Weg für schnelle Prototypen. In Kundenprojekten nutze ich push nicht.

Zwei Dinge gehören dazu, die keine Bibliothek abnimmt. Erstens Sperren: PostgreSQL nimmt für viele Formen von ALTER TABLE laut Doku zu Sperren eine Sperre der Stufe ACCESS EXCLUSIVE, und nur diese Stufe blockiert auch ein einfaches SELECT. Eine Änderung an einer großen, viel gelesenen Tabelle plane ich deshalb außerhalb der Hauptzeiten. Zweitens die Reihenfolge. Die Prisma-Anleitung zu Datenmigrationen beschreibt das Muster Erweitern und Zusammenziehen: erst die neue Spalte anlegen und Daten kopieren, dann die Anwendung umstellen, und erst wenn nichts mehr die alte Spalte liest oder schreibt, sie in einer zweiten Migration entfernen. So läuft die alte Programmversion weiter, solange die neue noch nicht überall ausgerollt ist.

Wo die Migration läuft, ist eine Designfrage. Drizzle nennt Migrationen beim Start der Anwendung als Option. Ich führe sie als eigenen Schritt vor dem Umschalten aus: Schlägt sie fehl, stoppt der Deploy, und die laufende Version bleibt unberührt.

#Backups: was ein Dump kann und was nicht

Die PostgreSQL-Doku nennt drei Wege: SQL-Dump, Backup auf Dateisystemebene und fortlaufende Archivierung. Für Anwendungen dieser Größe zählen zwei.

Der Dump mit pg_dump ist laut Doku in sich konsistent: Er bildet den Stand der Datenbank zu dem Zeitpunkt ab, zu dem pg_dump gestartet ist, und blockiert andere Vorgänge nicht, abgesehen von solchen, die eine exklusive Sperre brauchen. Das Format -Fc wird komprimiert, und man stellt damit mit pg_restore auch einzelne Tabellen her. Was der Dump nicht kann: den Stand von vor zehn Minuten rekonstruieren, wenn er seit zwölf Stunden alt ist.

Dafür gibt es die fortlaufende Archivierung: ein Basis-Backup plus eine lückenlose Folge archivierter WAL-Dateien. Man kann dann die Wiedergabe an einem beliebigen Zeitpunkt nach dem Basis-Backup anhalten, etwa kurz bevor jemand die falsche Tabelle gelöscht hat. Die Doku weist darauf hin, dass Dumps dafür nicht taugen, weil sie logisch sind und nicht genug Information für die WAL-Wiedergabe enthalten, und dass immer der ganze Cluster wiederhergestellt wird.

Welcher Weg passt, ist eine Frage an Sie: Wie viel Arbeit dürfen Sie im Ernstfall verlieren, und wie lange darf die Wiederherstellung dauern? Ich schreibe beides vor dem Start auf. Dazu gehört ein Restore-Test auf einer frischen Datenbank, denn ein Backup, das nie zurückgespielt wurde, ist nur eine Vermutung. Die Sicherungen liegen außerhalb des Hostings der Datenbank.

Eine Terminfrage gehört ebenfalls hierher. Laut Versionierungsseite erscheint für PostgreSQL 14 am 12. November 2026 die letzte Aktualisierung (Stand 11. November 2026). Danach erhält die Version keine Sicherheitskorrekturen mehr. Aktuell ist PostgreSQL 18, dessen Unterstützung bis zum 14. November 2030 läuft. Wer noch auf 14 oder 15 läuft, bekommt von mir ein schriftliches Upgrade-Vorhaben mit Probelauf auf einer Kopie.

#Sachsen: was die Aufsicht 2026 meldet

Zuständig für Unternehmen im Freistaat ist die Sächsische Datenschutz- und Transparenzbeauftragte (SDTB) mit Sitz in Dresden. Sie hat am 8. November 2026 Zahlen veröffentlicht, die für jede Anwendung mit Kundendaten relevant sind: Bis Ende September gingen 1.836 Beschwerden ein, 52 Prozent mehr als im Vorjahreszeitraum, im nichtöffentlichen Bereich 62 Prozent mehr. Meldungen von Datenpannen nach Art. 33 DSGVO zählte sie bis Ende Oktober 1.400, im gesamten Jahr 2025 waren es 1.058. Die SDTB schreibt, dass zu den Meldungen mehr und mehr Cyberangriffe gehören, bei denen auch Gesundheits- und Finanzdaten betroffen sind. Quelle: Mitteilung der SDTB.

Für die Datenbank folgt daraus nichts Neues, aber etwas Konkretes. Zugangsdaten gehören in Umgebungsvariablen und nur in die DAL, die Datenbank ist nicht aus dem Internet erreichbar, und Backups enthalten dieselben Personendaten wie die Datenbank und brauchen denselben Schutz. Ob eine Datenpanne meldepflichtig ist, entscheidet der Verantwortliche, also Sie. Von mir bekommen Sie die technische Zeitachse: betroffene Daten, Beginn, getroffene Maßnahmen. Die Meldung selbst geht über das Formular der SDTB.

#Prüfliste für Ihre Anwendung

PrüfpunktWoran Sie es erkennen
Alle Abfragen laufen in einer DatenzugriffsschichtDatenbank-Pakete werden nur dort importiert
Die Schicht ist mit server-only markiertBuild bricht bei Import im Client ab
Abfragen liefern nur benötigte SpaltenRückgabewerte der DAL lesen
Pool-Größe mal Instanzen liegt unter dem LimitRechnung gegen max_connections
Bei Funktionen ohne Dauerlauf steht ein Pooler davorVerbindungs-URL der Anwendung prüfen
Migrationen laufen als eigener Pipeline-SchrittPipeline-Datei lesen
Vorschau-Deployments haben eine eigene DatenbankUmgebungsvariablen vergleichen
Der Migrationsschritt nutzt eine direkte VerbindungURL des Schritts prüfen
Wiederherstellung ist getestetDatum des letzten Restore-Tests
Die PostgreSQL-Version wird noch unterstütztSELECT version();

#Wie ein Projekt mit mir abläuft

Ich arbeite allein, aus der Ferne und schriftlich, ohne Termine und Telefonate. Sie schicken mir den Anlass: eine neue Anwendung oder eine bestehende, die langsam wird oder deren Datenbank niemand mehr richtig kennt. Ich antworte mit Rückfragen und einer schriftlichen Beschreibung von Umfang und Annahmen, darin das Datenmodell als Entwurf, die Wahl von Prisma oder Drizzle samt Begründung und die Angaben zu Backup und Wiederherstellung. Gebaut wird auf einer Staging-Umgebung mit eigener Datenbank. Sie prüfen dort, geben schriftlich frei, dann folgt der Livegang mit dem Migrationsschritt. Auf Wunsch übernehme ich danach Updates; Stunden wandern nicht in den nächsten Monat.

Zum Start brauche ich Zugang zum Repository oder zur bestehenden Anwendung, eine Beschreibung der Daten (welche Objekte, wer sie sieht, wie viele es etwa sind) und das Layout der Oberflächen als Wireframe. Die Gestaltung bringen Sie mit, die Umsetzung übernehme ich.

#Weitere Seiten zu Dresden

Eine klassische Website mit Redaktion beschreibt die Seite zu WordPress in Dresden, die Pflege laufender Systeme die zu Wartung und Support in Dresden. Wer ein bestehendes System auf Next.js oder Astro umziehen will, findet den Ablauf unter Migration in Dresden.

#Fragen zu Datenbank und Next.js

Prisma oder Drizzle, was nehmen Sie? Das entscheide ich nach dem Team. Wer SQL liest und jede Migrationsdatei prüfen will, ist mit Drizzle gut bedient, weil Drizzle Kit pro Änderung eine SQL-Datei erzeugt. Wer ein Schema in einer eigenen Sprache und einen generierten Client bevorzugt, nimmt Prisma. Beide arbeiten mit PostgreSQL. Auf npm zeigt der Tag latest bei Prisma im November 2026 auf 8.0.0-rc.33, die neueste 7er-Version ist 7.10.1; bei Drizzle ORM ist es 0.45.4.

Darf ich die Datenbank direkt in der Server Component abfragen? Technisch ja, die Next.js-Doku zeigt es. Für neue Projekte empfiehlt dieselbe Doku aber eine Datenzugriffsschicht, die nur auf dem Server läuft, Berechtigungen prüft und schmale Datenobjekte liefert. Abfragen direkt in der Komponente nennt sie eine Lösung für Prototypen.

Wie viele Datenbankverbindungen darf meine Anwendung öffnen? Das Produkt aus Pool-Größe und Zahl der Instanzen muss unter dem Limit von PostgreSQL bleiben. Standardmäßig sind das 100 Verbindungen, drei davon sind für Superuser reserviert. Bei Funktionen ohne Dauerlauf bekommt jede Instanz einen eigenen Pool; dort schaltet man einen Pooler wie PgBouncer vor die Datenbank.

Sollen Migrationen beim Start der Anwendung laufen? Ich führe sie als eigenen Schritt der Pipeline aus, vor dem Umschalten auf die neue Version. Drizzle nennt Migrationen beim Start als Möglichkeit für Monolithen und Serverless; ich bevorzuge den getrennten Schritt, weil ein Fehler dann den Deploy stoppt und nicht erst die laufende Anwendung.

Genügt ein nächtlicher pg_dump als Backup? Er ist ein gültiger Schnappschuss vom Beginn des Laufs, mehr nicht. Die Änderungen seitdem fehlen. Wer auf den Moment vor einem Fehler zurückspringen muss, braucht laut PostgreSQL-Doku ein Basis-Backup plus archivierte WAL-Dateien. Ob das nötig ist, hängt davon ab, wie viel Arbeit Sie im Ernstfall verlieren dürfen.

Gestalten Sie auch die Oberfläche? Nein. Das Layout samt Mockups und Wireframes kommt von Ihnen. In einer Tabellenvorlage tragen Sie ein, welches Element wohin gehört, und ich setze das responsiv um. Das Datenmodell entwerfe ich aus Ihren schriftlichen Anforderungen und stimme es mit Ihnen ab.

#Schreiben Sie mir zu Ihrer Datenbank

Planen Sie in Dresden eine Anwendung mit PostgreSQL, oder soll eine bestehende ihre Verbindungen, Migrationen und Backups in Ordnung bringen? Schreiben Sie mir über das Kontaktformular: die Adresse der Anwendung, was gespeichert wird, den vorhandenen Stack und Ihren Wunschtermin. Meine erste Einschätzung zu Ihrem Vorhaben liefere ich schriftlich und unentgeltlich. Ich antworte an Werktagen schriftlich, zuerst mit Rückfragen.

Brauchen Sie die Leistung: Next.js-Entwickler in Dresden?

Beschreiben Sie Ihr Projekt per E-Mail. Antwort innerhalb von 48 Stunden.

Projekt beschreiben

Weitere WordPress-Dienste und Wissensbasis entdecken