Communitygithub.com

Patrones de Neon Serverless PostgreSQL

PostgreSQL serverless con branch (ramificación), autoescalado y controlador compatible con edge.

¿Qué es Patrones de Neon Serverless PostgreSQL?

Esta skill proporciona las mejores prácticas y patrones para usar Neon, una base de datos PostgreSQL serverless que separa almacenamiento y cómputo, permitiendo características como scale-to-zero, branching instantáneo y autoescalado. Se enfoca en el uso del controlador `@neondatabase/serverless`, que reemplaza TCP con HTTP y WebSockets para funcionar en entornos edge y serverless. Los patrones principales incluyen: consultas HTTP rápidas con la función `neon()` (recomendada para consultas individuales), conexiones WebSocket con `Pool`/`Client` para transacciones interactivas, manejo de cadenas de conexión agrupadas (`-pooler`) versus directas, branching de bases de datos para entornos de desarrollo y previsualización, y estrategias para mitigar arranques en frío de 200-500ms. La skill también enfatiza la seguridad contra inyección SQL mediante el uso de templates etiquetados y la importancia de cerrar las conexiones dentro del mismo manejador de solicitudes en entornos serverless.

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

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace Patrones de Neon Serverless PostgreSQL?

Guía rápida: Usa @neondatabase/serverless para acceso a bases de datos en entornos edge/serverless. Prefiere la función HTTP neon() para consultas individuales (más rápida, sin estado) y Pool/Client para transacciones interactivas. Usa cadenas de conexión agrupadas (sufijo -pooler) para cargas de trabajo serverless; conexiones directas solo para migraciones. Ramifica tu base de datos para entornos de desarrollo/previsualización usando semántica copy-on-write. Siempre maneja los arranques en frío por scale-to-zero (200-500ms de activación).


<critical_requirements>

CRÍTICO: Antes de Usar Esta Skill

Todo el código debe seguir las convenciones del proyecto en CLAUDE.md (kebab-case, exportaciones nombradas, orden de importaciones, import type, constantes nombradas)

(DEBES usar la función HTTP neon() para consultas individuales en entornos edge/serverless -- es 2-3 veces más rápida que WebSocket para operaciones de una sola consulta)

(DEBES cerrar las conexiones Pool/Client dentro del mismo manejador de solicitudes en entornos serverless -- las conexiones WebSocket no pueden superar la vida de una sola solicitud)

(DEBES usar cadenas de conexión agrupadas (sufijo -pooler) para cargas de trabajo serverless -- las conexiones directas agotan los slots de conexión limitados)

(DEBES manejar la latencia de activación por scale-to-zero (200-500ms) con tiempos de espera de conexión y lógica de reintento adecuados)

(DEBES usar sql.unsafe() solo para cadenas confiables y conocidas como nombres de tablas/columnas -- nunca para entrada del usuario)

</critical_requirements>


Detección automática: 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

Cuándo usar:

  • Consultar Postgres desde funciones edge/serverless (entornos edge, plataformas serverless)
  • Configurar cadenas de conexión (agrupadas vs directas) para diferentes cargas de trabajo
  • Crear ramas de base de datos para entornos de desarrollo, previsualización o CI
  • Gestionar el comportamiento de scale-to-zero y la optimización de arranque en frío
  • Ejecutar transacciones en contextos serverless (lote HTTP o WebSocket)
  • Gestión programática de ramas mediante la API de Neon o la CLI neonctl

Patrones clave cubiertos:

  • Consultas HTTP neon() con templates etiquetados SQL y fragmentos componibles
  • Conexiones WebSocket Pool/Client con gestión de ciclo de vida adecuada
  • Cadenas de conexión agrupadas (-pooler) vs directas y cuándo usar cada una
  • Ramificación de bases de datos (ramas de desarrollo, ramas de previsualización PR, ramas solo de esquema)
  • Comportamiento de scale-to-zero, mitigación de arranque en frío y autoescalado
  • sql.transaction() para transacciones HTTP no interactivas
  • API de Neon y CLI neonctl para gestión programática de ramas

Cuándo NO usar:

  • Conexiones de servidor tradicionales de larga duración (usa el controlador pg estándar con TCP)
  • Patrones complejos específicos de ORM (usa la skill de tu propio ORM)
  • Sintaxis general de consultas PostgreSQL (usa una skill de SQL/Postgres)

Recursos detallados:

  • Para marcos de decisión y tablas de referencia rápida, consulta reference.md

Controlador y Consultas:

  • examples/core.md -- Configuración del controlador, consultas HTTP, conexiones WebSocket, transacciones

Ramificación y Operaciones:

  • examples/branching.md -- Ramas de desarrollo, previsualizaciones PR, CLI neonctl, API de Neon, flujos CI/CD

Filosofía

Neon separa almacenamiento y cómputo para PostgreSQL, habilitando características serverless imposibles con Postgres tradicional: scale-to-zero, ramificación instantánea y autoescalado. El controlador @neondatabase/serverless reemplaza TCP con HTTP y WebSockets, haciendo que Postgres sea accesible desde entornos edge que no admiten TCP.

Principios fundamentales:

  1. HTTP para velocidad, WebSocket para sesiones -- La función neon() usa HTTP fetch (~3 viajes de ida y vuelta) para consultas individuales. Pool/Client usan WebSockets (~8 viajes de ida y vuelta) cuando necesitas sesiones o transacciones interactivas. Elige el transporte adecuado para el trabajo.
  2. Agrupado por defecto -- Las conexiones agrupadas se enrutan a través de PgBouncer (modo transacción), manejando hasta 10,000 clientes concurrentes. Las conexiones directas están limitadas por el tamaño de cómputo (100-4,000) y solo deben usarse para migraciones o funciones que requieran estado de sesión.
  3. Las ramas son baratas -- Copy-on-write significa que una rama de una base de datos de 500 GB no asigna almacenamiento adicional hasta que los datos divergen. Usa ramas libremente para desarrollo, previsualización, pruebas y CI.
  4. Scale-to-zero es el valor predeterminado -- Los cómputos se suspenden después de 5 minutos de inactividad. Los arranques en frío tardan 200-500ms. Diseña para esto con tiempos de espera, reintentos y agrupación de conexiones.
  5. Seguridad contra inyección SQL incorporada -- La función de template etiquetado parametriza automáticamente. Desde v1.0, llamar a neon() como una función regular es un error de tipo, lo que previene la inyección accidental.

Cuándo usar el controlador serverless de Neon:

  • Funciones edge/serverless que no pueden abrir conexiones TCP
  • Aplicaciones que se benefician de la ramificación de bases de datos (entornos de previsualización por PR)
  • Cargas de trabajo sensibles al costo que se benefician de scale-to-zero
  • Aplicaciones serverless de alta concurrencia que necesitan agrupación de conexiones

Cuándo NO usar:

  • Procesos de servidor de larga duración con conexiones persistentes (usa pg estándar sobre TCP)
  • Cargas de trabajo que requieren características a nivel de sesión a través de PgBouncer (LISTEN/NOTIFY, SET, tablas temporales)
  • Bases de datos mayores de 16 CU que necesitan cómputo siempre activo (scale-to-zero no disponible por encima de 16 CU)

Patrones Principales

Patrón 1: Consultas HTTP con neon()

La función neon() crea una función de consulta basada en HTTP usando templates etiquetados SQL. Es la ruta más rápida para consultas individuales no interactivas.

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

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

// Template etiquetado -- los parámetros se parametrizan automáticamente (seguro contra inyección)
const userId = "abc-123";
const posts =
  await sql`SELECT id, title FROM posts WHERE author_id = ${userId}`;

Por qué es bueno: El template etiquetado parametriza automáticamente los valores previniendo la inyección SQL, HTTP tiene ~3 viajes de ida y vuelta vs ~8 para WebSocket, sin estado (sin conexión que gestionar)

// MALO: Llamar a neon() como una función regular (error de tipo desde v1.0+)
const sql = neon(DATABASE_URL);
const result = await sql(`SELECT * FROM posts WHERE id = ${id}`); // ERROR DE TIPO + riesgo de inyección SQL

Por qué es malo: Desde v1.0, llamar a la función de consulta como una función regular (no un template etiquetado) es un error en tiempo de ejecución y de tipo -- esto se cambió específicamente para prevenir la inyección SQL por interpolación de cadenas

sql.query() para SQL Dinámico

Cuando la cadena de consulta está en una variable (no un literal de template), usa el método .query() con marcadores de posición numerados:

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

Cuándo usarlo: Cadenas SQL dinámicas construidas en tiempo de ejecución, o consultas almacenadas en variables. Los parámetros aún se parametrizan de forma segura mediante $1, $2, etc.


Patrón 2: Fragmentos de Consulta Componibles

Las consultas con template admiten composición con numeración automática de parámetros entre fragmentos.

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

const sql = neon(DATABASE_URL);

// Construye consultas a partir de fragmentos reutilizables
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}`;

Por qué es bueno: Los parámetros se renumeran automáticamente entre fragmentos compuestos, constante nombrada para el tamaño de página, los fragmentos son reutilizables entre consultas

Nombres Dinámicos de Tablas/Columnas con sql.unsafe()

// SOLO para valores confiables y conocidos -- nunca entrada del usuario
const TABLE_NAME = "posts";
const results =
  await sql`SELECT * FROM ${sql.unsafe(TABLE_NAME)} WHERE id = ${postId}`;

Cuándo usarlo: Solo cuando necesitas interpolar identificadores confiables (nombres de tablas, columnas) que no se pueden parametrizar en SQL. Nunca pases valores proporcionados por el usuario a sql.unsafe().


Patrón 3: Transacciones HTTP con sql.transaction()

Ejecuta múltiples consultas atómicamente a través de HTTP sin necesidad de una conexión WebSocket.

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

const sql = neon(DATABASE_URL);

// Forma de arreglo -- todas las consultas se ejecutan en un solo viaje de ida y vuelta 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`,
]);

// Forma de función con opciones de transacción
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" },
);

Por qué es bueno: Ejecución atómica sin sobrecarga de WebSocket, la forma de arreglo es concisa para lotes de solo lectura, la forma de función admite opciones de transacción, el nivel de aislamiento controla las garantías de consistencia

// MALO: Ejecutar consultas relacionadas como solicitudes HTTP separadas
const posts = await sql`SELECT * FROM posts WHERE author_id = ${authorId}`;
const author = await sql`SELECT * FROM users WHERE id = ${authorId}`;
// Dos viajes de ida y vuelta HTTP separados, no atómico, posibles condiciones de carrera

Por qué es malo: Llamadas HTTP separadas no son atómicas, los datos pueden cambiar entre consultas, el doble de latencia de red

Opciones de Transacción

  • isolationLevel: ReadUncommitted | ReadCommitted | RepeatableRead | Serializable
  • readOnly: booleano (predeterminado false)
  • deferrable: booleano (predeterminado false, solo efectivo con readOnly: true + Serializable)

Patrón 4: Conexiones WebSocket con Pool/Client

Usa Pool y Client para transacciones interactivas o compatibilidad con la API de node-postgres. En entornos serverless, las conexiones deben crearse y cerrarse dentro de un solo manejador de solicitudes.

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

export async function handleRequest(request: Request): Promise<Response> {
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });
  try {
    // ... consultas ...
  } finally {
    await pool.end(); // SIEMPRE cerrar dentro de la misma solicitud
  }
}

Regla clave: Crea Pool dentro del manejador, ciérralo con pool.end() en finally. Un Pool global filtra conexiones WebSocket entre invocaciones serverless.

Consulta examples/core.md -- Patrones 5-7 para pools con ámbito de solicitud, transacciones interactivas y configuración de WebSocket en Node.js.


Patrón 5: Configuración de Cadenas de Conexión

Neon proporciona dos formatos de cadena de conexión: agrupada (a través de PgBouncer) y directa.

# Conexión agrupada (nota: sufijo -pooler en el ID del endpoint)
# Usar para: funciones serverless, aplicaciones web, cargas de trabajo de alta concurrencia
DATABASE_URL=postgresql://user:[email protected]/dbname?sslmode=require

# Conexión directa (sin sufijo -pooler)
# Usar para: migraciones, pg_dump, LISTEN/NOTIFY, características a nivel de sesión
DIRECT_DATABASE_URL=postgresql://user:[email protected]/dbname?sslmode=require

Por qué es bueno: La agrupada maneja hasta 10,000 clientes concurrentes a través de PgBouncer en modo transacción, la directa proporciona características de sesión completas para tareas administrativas, variables de entorno separadas hacen explícita la distinción

Limitaciones del Modo Transacción de PgBouncer

La conexión agrupada ejecuta PgBouncer en modo transacción, lo que significa que las conexiones regresan al pool después de cada transacción. Esto prohíbe:

  • Sentencias SET / RESET (usa ALTER ROLE ... SET en su lugar)
  • LISTEN / NOTIFY
  • WITH HOLD CURSOR
  • PREPARE / DEALLOCATE a nivel SQL (se admiten sentencias preparadas a nivel de protocolo hasta 1,000)
  • Tablas temporales con PRESERVE / DELETE ROWS
  • Bloqueos de asesoramiento a nivel de sesión

Patrón 6: Manejo de Arranque en Frío y Scale-to-Zero

Los cómputos de Neon se auto-suspenden después de 5 minutos de inactividad (predeterminado). Los arranques en frío toman 200-500ms. Diseña para esto con tiempos de espera y lógica de reintento adecuados.

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

Regla clave: Establece tiempos de espera explícitos (10-15s) para acomodar la latencia de arranque en frío. Usa reintentos de backoff exponencial para confiabilidad.

Consulta examples/core.md -- Patrón 8 para configuración completa de tiempo de espera y patrones de reintento.

Hechos sobre Scale-to-Zero

  • Auto-suspensión predeterminada: 5 minutos de inactividad
  • Latencia de arranque en frío: ~200-500ms (varía según región y tamaño de cómputo)
  • Solo disponible para cómputos hasta 16 CU (los cómputos más grandes permanecen siempre activos)
  • Los planes de pago pueden ajustar el tiempo de espera de suspensión (hasta 7 días) o deshabilitarlo por completo
  • Los suscriptores de replicación lógica activa evitan la suspensión

Patrón 7: Ramificación de Bases de Datos

Las ramas de Neon usan semántica copy-on-write -- ramificar una base de datos de 500 GB es instantáneo y no asigna almacenamiento adicional hasta que los datos divergen.

# Instalar neonctl
npm install -g neonctl

# Crear una rama de desarrollo desde main
neonctl branches create --name dev-alice --project-id <id-proyecto>

# Crear una rama con vencimiento automático (para CI/previsualización)
neonctl branches create --name preview/pr-42 --project-id <id-proyecto> --expires-at "2025-04-01T00:00:00Z"

# Crear rama solo de esquema (sin copia de datos -- para entornos sensibles)
neonctl branches create --name ci-test --schema-only --project-id <id-proyecto>

# Restablecer una rama de desarrollo para que coincida con la producción actual
neonctl branches reset dev-alice --parent --project-id <id-proyecto>

# Eliminar una rama
neonctl branches delete preview/pr-42 --project-id <id-proyecto>

Por qué es bueno: Las ramas nombradas se asignan al flujo de trabajo de git, el vencimiento TTL limpia automáticamente las ramas de CI, la ramificación solo de esquema protege datos sensibles, el restablecimiento sincroniza el desarrollo con la producción sin necesidad de recrear

... [truncado para traducción]

Individual skills in this repo

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

Skills relacionados