Communitygithub.com

agents-inc/skills

PostgreSQL serverless avec branchement, mise à l'échelle automatique et pilote compatible edge

Qu'est-ce que skills ?

Cette compétence fournit des modèles pour utiliser Neon Serverless PostgreSQL de manière optimale dans les environnements edge et sans serveur. Elle couvre l'utilisation du pilote `@neondatabase/serverless` avec la fonction `neon()` pour les requêtes HTTP rapides (2-3x plus rapide que WebSocket pour des opérations uniques) et `Pool`/`Client` pour les transactions interactives. La compétence met l'accent sur l'utilisation de chaînes de connexion mises en commun (suffixe `-pooler`) pour les charges de travail sans serveur, la gestion des redémarrages à froid (200-500ms), et la création de branches de base de données pour les environnements de développement et d'aperçu via l'API Neon ou l'outil en ligne de commande `neonctl`. Elle détaille également la composition de requêtes avec des fragments, les transactions HTTP, et les limites du mode transaction de PgBouncer. Les utilisateurs apprendront à optimiser les performances, à éviter les injections SQL avec les modèles taggés, et à exploiter la copie sur écriture pour un branchement économique.

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

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Modèles Neon Serverless PostgreSQL

Guide rapide : Utilisez @neondatabase/serverless pour l'accès aux bases de données en edge/sans serveur. Préférez la fonction neon() HTTP pour les requêtes uniques (plus rapide, sans état) et Pool/Client pour les transactions interactives. Utilisez les chaînes de connexion mises en commun (suffixe -pooler) pour les charges de travail sans serveur, et les connexions directes uniquement pour les migrations. Créez des branches de votre base de données pour les environnements de développement/aperçu en utilisant la sémantique de copie sur écriture. Gérez toujours les redémarrages à froid (200-500ms).


<exigences_critiques>

CRITIQUE : Avant d'utiliser cette compétence

Tout le code doit suivre les conventions du projet dans CLAUDE.md (kebab-case, exportations nommées, ordre des importations, import type, constantes nommées)

(Vous DEVEZ utiliser la fonction HTTP neon() pour les requêtes uniques dans les environnements edge/sans serveur – elle est 2 à 3 fois plus rapide que WebSocket pour les opérations ponctuelles)

(Vous DEVEZ fermer les connexions Pool/Client dans le même gestionnaire de requête dans les environnements sans serveur – les connexions WebSocket ne peuvent pas survivre à une seule requête)

(Vous DEVEZ utiliser les chaînes de connexion mises en commun (suffixe -pooler) pour les charges de travail sans serveur – les connexions directes épuisent les créneaux de connexion limités)

(Vous DEVEZ gérer la latence de réveil (200-500ms) avec des délais d'attente de connexion et une logique de nouvelle tentative appropriés)

(Vous DEVEZ utiliser sql.unsafe() uniquement pour les chaînes de confiance connues comme les noms de table/colonne – jamais pour les entrées utilisateur)

</exigences_critiques>


Détection automatique : Neon, @neondatabase/serverless, neon(), neonConfig, neon serverless driver, neon database, neon branch, neonctl, neon connection pooling, neon scale-to-zero, neon autoscaling, neon postgres, ep-*-pooler

Quand l'utiliser :

  • Interroger Postgres depuis des fonctions edge/sans serveur (environnements edge, plateformes sans serveur)
  • Configurer des chaînes de connexion (mises en commun vs directes) pour différentes charges de travail
  • Créer des branches de base de données pour les environnements de développement, d'aperçu ou CI
  • Gérer le comportement de mise à l'échelle à zéro et l'optimisation des départs à froid
  • Exécuter des transactions dans des contextes sans serveur (lot HTTP ou WebSocket)
  • Gestion programmatique des branches via l'API Neon ou l'outil CLI neonctl

Modèles clés couverts :

  • Requêtes HTTP neon() avec modèles taggés SQL et fragments composables
  • Connexions WebSocket Pool/Client avec une gestion de cycle de vie appropriée
  • Chaînes de connexion mises en commun (-pooler) vs directes et quand utiliser chacune
  • Création de branches de base de données (branches de développement, branches d'aperçu PR, branches de schéma uniquement)
  • Comportement de mise à l'échelle à zéro, atténuation des départs à froid et mise à l'échelle automatique
  • sql.transaction() pour les transactions HTTP non interactives
  • API Neon et outil CLI neonctl pour la gestion programmatique des branches

Quand NE PAS l'utiliser :

  • Connexions serveur longue durée traditionnelles (utilisez le pilote pg standard avec TCP)
  • Modèles ORM complexes spécifiques (utilisez la compétence de votre propre ORM)
  • Syntaxe générale des requêtes PostgreSQL (utilisez une compétence SQL/Postgres)

Ressources détaillées :

  • Pour les cadres de décision et les tableaux de référence rapide, voir reference.md

Pilote et requêtes :

  • examples/core.md – Configuration du pilote, requêtes HTTP, connexions WebSocket, transactions

Branchement et opérations :

  • examples/branching.md – Branches de développement, aperçus PR, outil CLI neonctl, API Neon, workflows CI/CD

Philosophie

Neon sépare le stockage et le calcul pour PostgreSQL, permettant des fonctionnalités sans serveur impossibles avec Postgres traditionnel : mise à l'échelle à zéro, branchement instantané et mise à l'échelle automatique. Le pilote @neondatabase/serverless remplace TCP par HTTP et WebSockets, rendant Postgres accessible depuis les environnements edge qui ne prennent pas en charge TCP.

Principes fondamentaux :

  1. HTTP pour la vitesse, WebSocket pour les sessions – La fonction neon() utilise HTTP fetch (~3 allers-retours) pour les requêtes uniques. Pool/Client utilise WebSockets (~8 allers-retours) lorsque vous avez besoin de sessions ou de transactions interactives. Choisissez le bon transport pour le travail.
  2. Mis en commun par défaut – Les connexions mises en commun sont acheminées via PgBouncer (mode transaction), gérant jusqu'à 10 000 clients simultanés. Les connexions directes sont limitées par la taille de calcul (100-4 000) et ne doivent être utilisées que pour les migrations ou les fonctionnalités nécessitant un état de session.
  3. Les branches sont peu coûteuses – La copie sur écriture signifie qu'une branche d'une base de données de 500 Go n'alloue aucun stockage supplémentaire jusqu'à ce que les données divergent. Utilisez les branches librement pour le développement, l'aperçu, les tests et l'IC.
  4. La mise à l'échelle à zéro est la valeur par défaut – Les calculs se suspendent après 5 minutes d'inactivité. Les départs à froid prennent 200 à 500 ms. Concevez en fonction de cela avec des délais d'attente, des tentatives et un regroupement de connexions.
  5. Protection contre les injections SQL intégrée – La fonction de modèle taggé paramètre automatiquement. Depuis la v1.0, appeler neon() en tant que fonction régulière est une erreur de type, empêchant les injections accidentelles.

Quand utiliser le pilote Neon serverless :

  • Fonctions edge/sans serveur qui ne peuvent pas ouvrir de connexions TCP
  • Applications bénéficiant du branchement de bases de données (environnements d'aperçu par PR)
  • Charges de travail sensibles aux coûts qui bénéficient de la mise à l'échelle à zéro
  • Applications sans serveur à haute concurrence nécessitant un regroupement de connexions

Quand NE PAS utiliser :

  • Processus serveur longue durée avec des connexions persistantes (utilisez pg standard sur TCP)
  • Charges de travail nécessitant des fonctionnalités au niveau de la session via PgBouncer (LISTEN/NOTIFY, SET, tables temporaires)
  • Bases de données de plus de 16 CU nécessitant un calcul toujours actif (la mise à l'échelle à zéro n'est pas disponible au-dessus de 16 CU)

<modèles>

Modèles principaux

Modèle 1 : Requêtes HTTP avec neon()

La fonction neon() crée une fonction de requête basée sur HTTP utilisant des modèles taggés SQL. C'est le chemin le plus rapide pour les requêtes uniques non interactives.

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

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

// Modèle taggé – les paramètres sont automatiquement paramétrés (protégés contre l'injection)
const userId = "abc-123";
const posts =
  await sql`SELECT id, title FROM posts WHERE author_id = ${userId}`;

Pourquoi c'est bon : Le modèle taggé paramètre automatiquement les valeurs empêchant l'injection SQL, HTTP est ~3 allers-retours contre ~8 pour WebSocket, sans état (aucune connexion à gérer)

// MAUVAIS : Appeler neon() en tant que fonction régulière (erreur de type v1.0+)
const sql = neon(DATABASE_URL);
const result = await sql(`SELECT * FROM posts WHERE id = ${id}`); // ERREUR DE TYPE + risque d'injection SQL

Pourquoi c'est mauvais : Depuis la v1.0, appeler la fonction de requête en tant que fonction régulière (pas un modèle taggé) est une erreur d'exécution et de type – cela a été modifié spécifiquement pour empêcher l'injection SQL via l'interpolation de chaîne

sql.query() pour SQL dynamique

Lorsque la chaîne de requête est dans une variable (pas un littéral de modèle), utilisez la méthode .query() avec des espaces réservés numérotés :

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

Quand l'utiliser : Chaînes SQL dynamiques construites à l'exécution, ou requêtes stockées dans des variables. Les paramètres sont toujours paramétrés en toute sécurité via $1, $2, etc.


Modèle 2 : Fragments de requête composables

Les requêtes par modèle prennent en charge la composition avec une numérotation automatique des paramètres entre fragments.

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

const sql = neon(DATABASE_URL);

// Construire des requêtes à partir de fragments réutilisables
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}`;

Pourquoi c'est bon : Les paramètres sont renumérotés automatiquement entre les fragments composés, constante nommée pour la taille de la page, les fragments sont réutilisables entre les requêtes

Noms de table/colonne dynamiques avec sql.unsafe()

// UNIQUEMENT pour les valeurs de confiance connues – jamais d'entrée utilisateur
const TABLE_NAME = "posts";
const results =
  await sql`SELECT * FROM ${sql.unsafe(TABLE_NAME)} WHERE id = ${postId}`;

Quand l'utiliser : Uniquement lorsque vous devez interpoler des identifiants de confiance (noms de table, noms de colonne) qui ne peuvent pas être paramétrés en SQL. Ne passez jamais de valeurs fournies par l'utilisateur à sql.unsafe().


Modèle 3 : Transactions HTTP avec sql.transaction()

Exécutez plusieurs requêtes de manière atomique via HTTP sans avoir besoin d'une connexion WebSocket.

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

const sql = neon(DATABASE_URL);

// Formulaire tableau – toutes les requêtes s'exécutent en un seul aller-retour HTTP
const [posts, totalCount] = await sql.transaction([
  sql`SELECT id, title FROM posts ORDER BY created_at DESC LIMIT 10`,
  sql`SELECT count(*) FROM posts`,
]);

// Formulaire fonction avec options de transaction
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" },
);

Pourquoi c'est bon : Exécution atomique sans surcharge WebSocket, le formulaire tableau est concis pour les lots en lecture seule, le formulaire fonction prend en charge les options de transaction, le niveau d'isolement contrôle les garanties de cohérence

// MAUVAIS : Exécution de requêtes connexes en tant que requêtes HTTP séparées
const posts = await sql`SELECT * FROM posts WHERE author_id = ${authorId}`;
const author = await sql`SELECT * FROM users WHERE id = ${authorId}`;
// Deux allers-retours HTTP séparés, non atomiques, conditions de concurrence possibles

Pourquoi c'est mauvais : Les appels HTTP séparés ne sont pas atomiques, les données peuvent changer entre les requêtes, double la latence du réseau

Options de transaction

  • isolationLevel : ReadUncommitted | ReadCommitted | RepeatableRead | Serializable
  • readOnly : booléen (par défaut false)
  • deferrable : booléen (par défaut false, efficace uniquement avec readOnly: true + Serializable)

Modèle 4 : Connexions WebSocket avec Pool/Client

Utilisez Pool et Client pour les transactions interactives ou la compatibilité avec l'API node-postgres. Dans les environnements sans serveur, les connexions doivent être créées et fermées dans un seul gestionnaire de requête.

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

export async function handleRequest(request: Request): Promise<Response> {
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });
  try {
    // ... requêtes ...
  } finally {
    await pool.end(); // TOUJOURS fermer dans la même requête
  }
}

Règle clé : Créez Pool à l'intérieur du gestionnaire, fermez avec pool.end() dans finally. Un Pool global fuit les connexions WebSocket entre les invocations sans serveur.

Voir examples/core.md – Modèles 5-7 pour les pools limités à la requête, les transactions interactives et la configuration WebSocket Node.js.


Modèle 5 : Configuration de la chaîne de connexion

Neon fournit deux formats de chaîne de connexion : mis en commun (via PgBouncer) et direct.

# Connexion mise en commun (remarque : suffixe -pooler sur l'ID de point de terminaison)
# Utilisation pour : fonctions sans serveur, applications web, charges de travail à haute concurrence
DATABASE_URL=postgresql://user:[email protected]/dbname?sslmode=require

# Connexion directe (pas de suffixe -pooler)
# Utilisation pour : migrations, pg_dump, LISTEN/NOTIFY, fonctionnalités au niveau de la session
DIRECT_DATABASE_URL=postgresql://user:[email protected]/dbname?sslmode=require

Pourquoi c'est bon : La mise en commun gère jusqu'à 10 000 clients simultanés via PgBouncer en mode transaction, la connexion directe fournit des fonctionnalités de session complètes pour les tâches d'administration, des variables d'environnement séparées rendent la distinction explicite

Limitations du mode transaction PgBouncer

La connexion mise en commun exécute PgBouncer en mode transaction, ce qui signifie que les connexions retournent au pool après chaque transaction. Cela interdit :

  • Les déclarations SET / RESET (utilisez ALTER ROLE ... SET à la place)
  • LISTEN / NOTIFY
  • WITH HOLD CURSOR
  • PREPARE / DEALLOCATE au niveau SQL (les déclarations préparées au niveau du protocole jusqu'à 1 000 sont prises en charge)
  • Tables temporaires avec PRESERVE / DELETE ROWS
  • Verrous consultatifs au niveau de la session

Modèle 6 : Gestion des redémarrages à froid et de la mise à l'échelle à zéro

Les calculs Neon s'auto-suspendent après 5 minutes d'inactivité (par défaut). Les redémarrages à froid prennent 200 à 500 ms. Concevez en fonction de cela avec des délais d'attente et une logique de nouvelle tentative appropriés.

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

Règle clé : Définissez des délais d'attente explicites (10-15s) pour tenir compte de la latence de redémarrage à froid. Utilisez des tentatives avec backoff exponentiel pour la fiabilité.

Voir examples/core.md – Modèle 8 pour la configuration complète des délais d'attente et les modèles de tentatives.

Faits sur la mise à l'échelle à zéro

  • Auto-suspension par défaut : 5 minutes d'inactivité
  • Latence de redémarrage à froid : ~200-500ms (varie selon la région et la taille de calcul)
  • Disponible uniquement pour les calculs jusqu'à 16 CU (les calculs plus grands restent toujours actifs)
  • Les formules payantes peuvent ajuster le délai de suspension (jusqu'à 7 jours) ou le désactiver complètement
  • Les abonnés à la réplication logique active empêchent la suspension

Modèle 7 : Création de branches de base de données

Les branches Neon utilisent la sémantique de copie sur écriture – la création d'une branche d'une base de données de 500 Go est instantanée et n'alloue aucun stockage supplémentaire jusqu'à ce que les données divergent.

# Installer neonctl
npm install -g neonctl

# Créer une branche de développement à partir de main
neonctl branches create --name dev-alice --project-id <project-id>

# Créer une branche avec expiration automatique (pour CI/aperçu)
neonctl branches create --name preview/pr-42 --project-id <project-id> --expires-at "2025-04-01T00:00:00Z"

# Créer une branche de schéma uniquement (aucune donnée copiée – pour les environnements sensibles)
neonctl branches create --name ci-test --schema-only --project-id <project-id>

# Réinitialiser une branche de développement pour correspondre à la production actuelle
neonctl branches reset dev-alice --parent --project-id <project-id>

# Supprimer une branche
neonctl branches delete preview/pr-42 --project-id <project-id>

Pourquoi c'est bon : Les branches nommées correspondent au workflow git, l'expiration TTL nettoie automatiquement les branches CI, le branchement de schéma uniquement protège les données sensibles, la réinitialisation synchronise le développement avec la production sans recréer

Individual skills in this repo

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

Skills associés