Communitygithub.com

Neon Serverless PostgreSQL Patterns

Serverless PostgreSQL mit Branching, Autoskalierung und Edge-kompatiblem Treiber

Was ist Neon Serverless PostgreSQL Patterns?

Dieses Skill beschreibt die Verwendung von Neons serverlosem PostgreSQL-Dienst mit dem `@neondatabase/serverless`-Treiber. Es konzentriert sich auf die Optimierung von Datenbankoperationen für Edge- und serverlose Laufzeitumgebungen, die kein herkömmliches TCP unterstützen. Das Skill behandelt zentrale Muster wie HTTP-basierte Abfragen mit der `neon()`-Funktion für schnelle, zustandslose Einzelabfragen und WebSocket-Verbindungen mit `Pool`/`Client` für interaktive Transaktionen. Wesentliche Konzepte sind die Pool-Verbindungsstrings (mit `-pooler`-Suffix) für serverlose Workloads im Vergleich zu direkten Verbindungen für administrative Aufgaben sowie die Verwendung von Datenbank-Branching mit Copy-on-Write-Semantik für Entwicklungs-, Vorschau- und CI-Umgebungen. Es werden Best Practices für die Behandlung von Kaltstarts (Scale-to-Zero mit 200-500 ms Aufwachzeit), korrekte Verbindungslebenszyklen in serverlosen Funktionen und Sicherheit vor SQL-Injection durch getaggte Vorlagen beschrieben. Das Skill ist plattformunabhängig für Neons Ökosystem (einschließlich `@neondatabase/serverless`, `neonctl`-CLI und Neon API) und bietet praktische Codebeispiele und Referenzen gängiger Fallstricke, um Entwicklern die Erstellung performanter, sicherer und wartbarer Anwendungen zu ermöglichen.

Funktioniert mit✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/agents-inc/skills/tree/HEAD/src/skills/api-baas-neon

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Was macht Neon Serverless PostgreSQL Patterns?

Kurzanleitung: Verwenden Sie @neondatabase/serverless für den Edge-/Serverless-Datenbankzugriff. Bevorzugen Sie die neon() HTTP-Funktion für einzelne Abfragen (schneller, zustandslos) und Pool/Client für interaktive Transaktionen. Verwenden Sie gepoolte Verbindungsstrings (-pooler-Suffix) für serverlose Workloads, direkte Verbindungen nur für Migrationen. Erstellen Sie Branches Ihrer Datenbank für Entwicklungs-/Vorschauumgebungen mit Copy-on-Write-Semantik. Behandeln Sie immer Kaltstarts durch Scale-to-Zero (200-500 ms Aufwachzeit).


<critical_requirements>

KRITISCH: Vor der Verwendung dieses Skills

Der gesamte Code muss die Projektkonventionen in CLAUDE.md befolgen (kebab-case, benannte Exporte, Importreihenfolge, import type, benannte Konstanten)

(Sie MÜSSEN die neon() HTTP-Funktion für einzelne Abfragen in Edge-/Serverless-Laufzeitumgebungen verwenden – sie ist 2-3x schneller als WebSocket für Einmaloperationen)

(Sie MÜSSEN Pool/Client-Verbindungen innerhalb desselben Request-Handlers in serverlosen Umgebungen schließen – WebSocket-Verbindungen können einen einzelnen Request nicht überdauern)

(Sie MÜSSEN gepoolte Verbindungsstrings (-pooler-Suffix) für serverlose Workloads verwenden – direkte Verbindungen erschöpfen die begrenzten Verbindungsslots)

(Sie MÜSSEN die Scale-to-Zero-Aufwachlatenz (200-500 ms) mit angemessenen Verbindungs-Timeouts und Wiederholungslogik behandeln)

(Sie MÜSSEN sql.unsafe() nur für vertrauenswürdige, bekanntermaßen sichere Zeichenfolgen wie Tabellen-/Spaltennamen verwenden – niemals für Benutzereingaben)

</critical_requirements>


Auto-Erkennung: Neon, @neondatabase/serverless, neon(), neonConfig, Neon Serverless-Treiber, Neon-Datenbank, Neon-Branch, neonctl, Neon-Verbindungspooling, Neon Scale-to-Zero, Neon-Autoskalierung, Neon-Postgres, ep-*-pooler

Wann verwenden:

  • Postgres aus Edge-/Serverless-Funktionen abfragen (Edge-Laufzeitumgebungen, Serverless-Plattformen)
  • Verbindungsstrings (gepoolt vs. direkt) für verschiedene Workloads einrichten
  • Datenbank-Branches für Entwicklungs-, Vorschau- oder CI-Umgebungen erstellen
  • Scale-to-Zero-Verhalten und Kaltstartoptimierung verwalten
  • Transaktionen in serverlosen Kontexten ausführen (HTTP-Batch oder WebSocket)
  • Programmatische Branch-Verwaltung über Neon API oder neonctl-CLI

Abgedeckte Schlüsselmuster:

  • neon() HTTP-Abfragen mit SQL-getaggten Vorlagen und zusammensetzbaren Fragmenten
  • Pool/Client WebSocket-Verbindungen mit ordnungsgemäßem Lebenszyklus-Management
  • Gepoolte (-pooler) vs. direkte Verbindungsstrings und wann sie verwendet werden
  • Datenbank-Branching (Entwicklungs-Branches, PR-Vorschau-Branches, Schema-only-Branches)
  • Scale-to-Zero-Verhalten, Kaltstartminderung und Autoskalierung
  • sql.transaction() für nicht-interaktive HTTP-Transaktionen
  • Neon API und neonctl-CLI für programmatische Branch-Verwaltung

Wann NICHT verwenden:

  • Traditionelle langlebige Serververbindungen (verwenden Sie den Standard-pg-Treiber über TCP)
  • Komplexe ORM-spezifische Muster (verwenden Sie das Skill Ihres ORMs)
  • Allgemeine PostgreSQL-Abfragesyntax (verwenden Sie ein SQL/Postgres-Skill)

Detaillierte Ressourcen:

  • Für Entscheidungsrahmen und Schnellnachschlagetabellen siehe reference.md

Treiber & Abfragen:

  • examples/core.md – Treibereinrichtung, HTTP-Abfragen, WebSocket-Verbindungen, Transaktionen

Branching & Operationen:


Philosophie

Neon trennt Speicher und Rechenleistung für PostgreSQL und ermöglicht serverlose Funktionen, die mit herkömmlichem Postgres unmöglich sind: Scale-to-Zero, sofortiges Branching und Autoskalierung. Der @neondatabase/serverless-Treiber ersetzt TCP durch HTTP und WebSockets und macht Postgres für Edge-Laufzeitumgebungen zugänglich, die kein TCP unterstützen.

Kernprinzipien:

  1. HTTP für Geschwindigkeit, WebSocket für Sitzungen – Die neon()-Funktion verwendet HTTP-Fetch (~3 Roundtrips) für einzelne Abfragen. Pool/Client verwenden WebSockets (~8 Roundtrips), wenn Sie Sitzungen oder interaktive Transaktionen benötigen. Wählen Sie den richtigen Transport für die Aufgabe.
  2. Standardmäßig gepoolt – Gepoolte Verbindungen werden über PgBouncer (Transaktionsmodus) geleitet und bewältigen bis zu 10.000 gleichzeitige Clients. Direkte Verbindungen sind durch die Computergröße begrenzt (100-4.000) und sollten nur für Migrationen oder Funktionen verwendet werden, die Sitzungsstatus erfordern.
  3. Branches sind günstig – Copy-on-Write bedeutet, dass ein Branch einer 500-GB-Datenbank keinen zusätzlichen Speicher zuweist, bis die Daten abweichen. Verwenden Sie Branches frei für Entwicklung, Vorschau, Tests und CI.
  4. Scale-to-Zero ist die Voreinstellung – Computes werden nach 5 Minuten Inaktivität ausgesetzt. Kaltstarts dauern 200-500 ms. Planen Sie dies mit Timeouts, Wiederholungen und Verbindungspooling ein.
  5. Sicherheit vor SQL-Injection integriert – Die getaggte Vorlagenfunktion parametrisiert automatisch. Seit v1.0 ist das Aufrufen von neon() als normale Funktion ein Typfehler, der unbeabsichtigte Injection verhindert.

Wann der Neon Serverless-Treiber verwendet werden sollte:

  • Edge-/Serverless-Funktionen, die keine TCP-Verbindungen öffnen können
  • Anwendungen, die von Datenbank-Branching profitieren (Vorschauumgebungen pro PR)
  • Kostenbewusste Workloads, die von Scale-to-Zero profitieren
  • Hochparallele Serverless-Apps, die Verbindungspooling benötigen

Wann NICHT verwenden:

  • Lang laufende Serverprozesse mit persistenten Verbindungen (verwenden Sie Standard-pg über TCP)
  • Workloads, die sitzungsbezogene Funktionen über PgBouncer erfordern (LISTEN/NOTIFY, SET, temporäre Tabellen)
  • Datenbanken größer als 16 CU, die ständig laufende Compute benötigen (Scale-to-Zero ist über 16 CU nicht verfügbar)

Kernmuster

Muster 1: HTTP-Abfragen mit neon()

Die neon()-Funktion erstellt eine HTTP-basierte Abfragefunktion mit SQL-getaggten Vorlagen. Dies ist der schnellste Weg für einzelne, nicht interaktive Abfragen.

import { neon } from "@neondatabase/serverless";

const DATABASE_URL = process.env.DATABASE_URL!;
const sql = neon(DATABASE_URL);

// Getaggte Vorlage – Parameter werden automatisch parametrisiert (sicher vor Injection)
const userId = "abc-123";
const posts =
  await sql`SELECT id, title FROM posts WHERE author_id = ${userId}`;

Warum gut: Die getaggte Vorlage parametrisiert Werte automatisch und verhindert SQL-Injection, HTTP ist ~3 Roundtrips vs. ~8 für WebSocket, zustandslos (keine zu verwaltende Verbindung)

// SCHLECHT: Aufruf von neon() als normale Funktion (v1.0+ Typfehler)
const sql = neon(DATABASE_URL);
const result = await sql(`SELECT * FROM posts WHERE id = ${id}`); // TYPFEHLER + SQL-Injection-Risiko

Warum schlecht: Seit v1.0 ist das Aufrufen der Abfragefunktion als normale Funktion (keine getaggte Vorlage) ein Laufzeit- und Typfehler – dies wurde speziell geändert, um SQL-Injection durch Zeichenfolgeninterpolation zu verhindern

sql.query() für dynamisches SQL

Wenn die Abfragezeichenfolge in einer Variable (kein Template-Literal) vorliegt, verwenden Sie die Methode .query() mit nummerierten Platzhaltern:

const q = "SELECT * FROM posts WHERE id = $1 AND status = $2";
const posts = await sql.query(q, [postId, "published"]);

Wann verwenden: Dynamische SQL-Zeichenfolgen, die zur Laufzeit erstellt werden, oder in Variablen gespeicherte Abfragen. Parameter werden weiterhin sicher über $1, $2 usw. parametrisiert.


Muster 2: Zusammensetzbare Abfragefragmente

Vorlagenabfragen unterstützen die Komposition mit automatischer Parameternummerierung über Fragmente hinweg.

import { neon } from "@neondatabase/serverless";

const sql = neon(DATABASE_URL);

// Erstellen Sie Abfragen aus wiederverwendbaren Fragmenten
const whereClause = sql`WHERE status = ${"active"} AND role = ${"admin"}`;
const orderClause = sql`ORDER BY created_at DESC`;
const PAGE_SIZE = 20;
const limitClause = sql`LIMIT ${PAGE_SIZE}`;

const users =
  await sql`SELECT id, name, email FROM users ${whereClause} ${orderClause} ${limitClause}`;

Warum gut: Parameter werden automatisch über zusammengesetzte Fragmente hinweg neu nummeriert, benannte Konstante für die Seitengröße, Fragmente sind über Abfragen hinweg wiederverwendbar

Dynamische Tabellen-/Spaltennamen mit sql.unsafe()

const TABLE_NAME = "posts";
const results =
  await sql`SELECT * FROM ${sql.unsafe(TABLE_NAME)} WHERE id = ${postId}`;

Wann verwenden: Nur wenn Sie vertrauenswürdige Identifikatoren (Tabellennamen, Spaltennamen) interpolieren müssen, die nicht in SQL parametrisiert werden können. Übergeben Sie niemals benutzergelieferte Werte an sql.unsafe().


Muster 3: HTTP-Transaktionen mit sql.transaction()

Führen Sie mehrere Abfragen atomar über HTTP aus, ohne eine WebSocket-Verbindung zu benötigen.

import { neon } from "@neondatabase/serverless";

const sql = neon(DATABASE_URL);

// Array-Form – alle Abfragen werden in einem einzigen HTTP-Roundtrip ausgeführt
const [posts, totalCount] = await sql.transaction([
  sql`SELECT id, title FROM posts ORDER BY created_at DESC LIMIT 10`,
  sql`SELECT count(*) FROM posts`,
]);

// Funktionsform mit Transaktionsoptionen
const [, transferResult] = await sql.transaction(
  (txn) => [
    txn`UPDATE accounts SET balance = balance - ${amount} WHERE id = ${fromId}`,
    txn`UPDATE accounts SET balance = balance + ${amount} WHERE id = ${toId}`,
  ],
  { isolationLevel: "Serializable" },
);

Warum gut: Atomare Ausführung ohne WebSocket-Overhead, Array-Form ist prägnant für schreibgeschützte Batches, Funktionsform unterstützt Transaktionsoptionen, Isolationsstufe steuert Konsistenzgarantien

// SCHLECHT: Ausführung verwandter Abfragen als separate HTTP-Anfragen
const posts = await sql`SELECT * FROM posts WHERE author_id = ${authorId}`;
const author = await sql`SELECT * FROM users WHERE id = ${authorId}`;
// Zwei separate HTTP-Roundtrips, nicht atomar, Race Conditions möglich

Warum schlecht: Separate HTTP-Aufrufe sind nicht atomar, Daten können sich zwischen Abfragen ändern, doppelte Netzwerklatenz

Transaktionsoptionen

  • isolationLevel: ReadUncommitted | ReadCommitted | RepeatableRead | Serializable
  • readOnly: boolean (Standard false)
  • deferrable: boolean (Standard false, nur wirksam mit readOnly: true + Serializable)

Muster 4: WebSocket-Verbindungen mit Pool/Client

Verwenden Sie Pool und Client für interaktive Transaktionen oder node-postgres-API-Kompatibilität. In serverlosen Umgebungen müssen Verbindungen innerhalb eines einzelnen Request-Handlers erstellt und geschlossen werden.

import { Pool } from "@neondatabase/serverless";

export async function handleRequest(request: Request): Promise<Response> {
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });
  try {
    // ... Abfragen ...
  } finally {
    await pool.end(); // IMMER innerhalb desselben Requests schließen
  }
}

Schlüsselregel: Erstellen Sie Pool innerhalb des Handlers, schließen Sie mit pool.end() in finally. Ein globaler Pool verliert WebSocket-Verbindungen zwischen serverlosen Aufrufen.

Siehe examples/core.md – Muster 5-7 für request-spezifische Pools, interaktive Transaktionen und Node.js-WebSocket-Konfiguration.


Muster 5: Einrichtung von Verbindungsstrings

Neon bietet zwei Formate für Verbindungsstrings: gepoolt (über PgBouncer) und direkt.

# Gepoolte Verbindung (Hinweis: -pooler-Suffix bei der Endpunkt-ID)
# Verwenden für: Serverless-Funktionen, Web-Apps, Workloads mit hoher Parallelität
DATABASE_URL=postgresql://user:[email protected]/dbname?sslmode=require

# Direkte Verbindung (kein -pooler-Suffix)
# Verwenden für: Migrationen, pg_dump, LISTEN/NOTIFY, sitzungsbezogene Funktionen
DIRECT_DATABASE_URL=postgresql://user:[email protected]/dbname?sslmode=require

Warum gut: Gepoolt bewältigt bis zu 10.000 gleichzeitige Clients über PgBouncer im Transaktionsmodus, direkt bietet vollständige Sitzungsfunktionen für Verwaltungsaufgaben, separate Umgebungsvariablen machen die Unterscheidung explizit

Einschränkungen des PgBouncer-Transaktionsmodus

Die gepoolte Verbindung führt PgBouncer im Transaktionsmodus aus, was bedeutet, dass Verbindungen nach jeder Transaktion an den Pool zurückgegeben werden. Dies verbietet:

  • SET / RESET-Anweisungen (verwenden Sie stattdessen ALTER ROLE ... SET)
  • LISTEN / NOTIFY
  • WITH HOLD CURSOR
  • PREPARE / DEALLOCATE auf SQL-Ebene (vorbereitete Anweisungen auf Protokollebene bis zu 1.000 werden unterstützt)
  • Temporäre Tabellen mit PRESERVE / DELETE ROWS
  • Sitzungsberatungssperren

Muster 6: Kaltstart- und Scale-to-Zero-Handhabung

Neon-Computes werden nach 5 Minuten Inaktivität (Standard) automatisch ausgesetzt. Kaltstarts dauern 200-500 ms. Planen Sie dies mit angemessenen Timeouts und Wiederholungslogik.

const CONNECTION_TIMEOUT_MS = 10_000;
const sql = neon(process.env.DATABASE_URL!, {
  fetchOptions: { signal: AbortSignal.timeout(CONNECTION_TIMEOUT_MS) },
});

Schlüsselregel: Legen Sie explizite Timeouts (10-15 s) fest, um die Kaltstartlatenz zu berücksichtigen. Verwenden Sie exponentielle Backoff-Wiederholungen für Zuverlässigkeit.

Siehe examples/core.md – Muster 8 für vollständige Timeout-Konfiguration und Wiederholungsmuster.

Scale-to-Zero-Fakten

  • Standard-Auto-Suspend: 5 Minuten Inaktivität
  • Kaltstartlatenz: ~200-500 ms (variiert je nach Region und Computergröße)
  • Nur für Computes bis zu 16 CU verfügbar (größere Computes bleiben ständig eingeschaltet)
  • Kostenpflichtige Pläne können das Suspend-Timeout anpassen (bis zu 7 Tage) oder vollständig deaktivieren
  • Aktive logische Replikationsabonnenten verhindern eine Suspendierung

Muster 7: Datenbank-Branching

Neon-Branches verwenden Copy-on-Write-Semantik – das Verzweigen einer 500-GB-Datenbank ist sofort und weist keinen zusätzlichen Speicher zu, bis die Daten abweichen.

# neonctl installieren
npm install -g neonctl

# Einen Entwicklungs-Branch von main erstellen
neonctl branches create --name dev-alice --project-id <project-id>

# Einen Branch mit automatischem Ablauf erstellen (für CI/Vorschau)
neonctl branches create --name preview/pr-42 --project-id <project-id> --expires-at "2025-04-01T00:00:00Z"

# Schema-only-Branch erstellen (keine Daten kopiert – für sensible Umgebungen)
neonctl branches create --name ci-test --schema-only --project-id <project-id>

# Einen Entwicklungs-Branch zurücksetzen, um ihn an die aktuelle Produktion anzupassen
neonctl branches reset dev-alice --parent --project-id <project-id>

# Einen Branch löschen
neonctl branches delete preview/pr-42 --project-id <project-id>

Warum gut: Benannte Branches entsprechen dem Git-Workflow, TTL-Ablauf bereinigt CI-Branches automatisch, Schema-only-Branching schützt sensible Daten, Zurücksetzen synchronisiert Entwicklung mit Produktion, ohne neu zu erstellen

Individual skills in this repo

This repo contains 11 individual skills — each has its own dedicated page.

Verwandte Skills