关于 api-database-vercel-postgres
面向维护和迁移 `@vercel/postgres` 项目的编码技能,涵盖连接池、直连、查询模式与边缘运行时注意事项。该包已弃用,技能建议新项目改用 `@neondatabase/serverless`。
主要功能
- 01使用 `sql` 执行参数化单次查询
- 02多查询会话与事务处理
- 03自定义连接池和客户端配置
- 04区分连接池连接与直接连接
- 05边缘运行时连接模式
- 06迁移至 `@neondatabase/serverless` 的指引
适用场景
- 01维护现有的 `@vercel/postgres` 应用
- 02在 Vercel 边缘或无服务器函数中查询数据库
- 03使用客户端在同一会话执行多条查询
- 04将应用迁移至 `@neondatabase/serverless`
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ agents-inc/ skills --skill api-database-vercel-postgres安装后在 Claude Code 中输入/api-database-vercel-postgres确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
metadata.yamlreference.mdexamples/core.md详细介绍
Vercel Postgres 模式
快速指南:
@vercel/postgres是@neondatabase/serverless的轻量封装,可从POSTGRES_URL环境变量自动连接。对于一次性查询,请使用sql标签模板(兼容边缘运行时,自动使用连接池)。对于多次查询序列,请使用sql.connect()获取客户端。在边缘运行时中,连接无法在不同请求之间重复使用(maxUses: 1)。此程序包已弃用(2024 年 12 月)——新项目请直接使用@neondatabase/serverless。
<critical_requirements>
重要:使用此技能前
所有代码都必须遵循项目在 CLAUDE.md 中的约定(kebab-case、命名导出、导入顺序、
import type、命名常量)
(一次性查询必须使用 sql 标签模板——它会从 POSTGRES_URL 自动连接并处理连接池)
(使用从 sql.connect() 或 pool.connect() 获取的客户端后,必须调用 client.release()——客户端泄漏会耗尽连接池)
(连接池连接必须使用 POSTGRES_URL,直接连接必须使用 POSTGRES_URL_NON_POOLING——混用会导致连接耗尽或功能受限)
(必须说明 @vercel/postgres 已弃用——新项目应使用 @neondatabase/serverless)
</critical_requirements>
自动检测: @vercel/postgres、vercel postgres、POSTGRES_URL、POSTGRES_URL_NON_POOLING、sql tagged template vercel、createPool vercel、createClient vercel、VercelPool、VercelClient
适用场景:
- 维护已在使用
@vercel/postgres的现有项目 - 在 Vercel 的边缘函数/无服务器函数中查询 Postgres
- 使用环境变量自动连接,进行简单的数据库访问
- 从
@vercel/postgres迁移到@neondatabase/serverless
涵盖的关键模式:
sql标签模板(自动使用连接池、兼容边缘运行时、用于一次性查询)- 使用
sql.connect()建立多次查询的客户端会话 - 使用
createPool()/createClient()进行自定义配置 - 环境变量(
POSTGRES_URL、POSTGRES_URL_NON_POOLING) - 边缘运行时与 Node.js 运行时的差异
- 迁移到
@neondatabase/serverless的路径
不适用场景:
- 新项目(请直接使用
@neondatabase/serverless) - 使用持久连接的长运行服务器进程(请使用标准
pg驱动程序) - 通用 PostgreSQL 查询语法(请使用 SQL/Postgres 技能)
详细资源:
- 决策框架和速查表,请参阅 reference.md
示例:
- examples/core.md —— sql 标签模板、createPool、createClient、边缘模式、迁移
## 设计理念
@vercel/postgres 是对 @neondatabase/serverless 的便捷封装,可简化 Vercel 部署应用的连接管理。它会从 POSTGRES_URL / POSTGRES_URL_NON_POOLING 环境变量读取连接字符串(由 Vercel Marketplace 集成自动配置),因此你无需手动构造连接字符串。
核心原则:
- 零配置连接 --
sql导出项会根据环境变量自动连接。无需在代码中设置连接字符串。 - 带标签模板的安全性 --
sql是带标签的模板字面量,而非函数。参数会自动参数化,从而防止 SQL 注入。 - 默认使用连接池 --
sql和createPool()使用连接池连接字符串(POSTGRES_URL)。createClient()使用直连字符串(POSTGRES_URL_NON_POOLING)。 - 适配边缘运行时 -- 在边缘运行时中,SDK 会设置
maxUses: 1,因为 IO 连接无法在请求之间保持。若要在单个请求中执行多个查询,请使用sql.connect()。
弃用背景:
Vercel Postgres 于 2024 年 12 月停止服务。所有数据库均已迁移至 Neon。@vercel/postgres npm 包(v0.10.0)已不再维护。迁移路径:
- 完整迁移(推荐):
@neondatabase/serverless(积极开发中,API 更丰富,支持 HTTP 事务和可组合片段)
核心模式
模式 1:使用 sql 执行一次性查询
sql 导出项是一个带标签的模板,会根据 POSTGRES_URL 自动连接。值会自动参数化(防止 SQL 注入)。完整示例和正反面对比请参阅 examples/core.md。
import { sql } from "@vercel/postgres";
const ACTIVE_STATUS = "active";
const { rows } =
await sql`SELECT id, name FROM users WHERE status = ${ACTIVE_STATUS}`;
模式 2:使用 sql.connect() 建立多查询会话
当你需要在同一连接上执行多个查询(事务、顺序操作)时,请获取一个客户端。每次独立的 sql 调用都可能使用不同的池化连接,因此在不同的 sql 调用中执行 BEGIN/COMMIT 并不能构成真正的事务。事务模式请参阅 examples/core.md。
const client = await sql.connect();
try {
await client.sql`BEGIN`;
// ... queries on same client ...
await client.sql`COMMIT`;
} catch (error) {
await client.sql`ROLLBACK`;
throw error;
} finally {
client.release();
}
模式 3:自定义连接池和客户端
使用 createPool() 配置自定义连接字符串(用于辅助数据库)。使用 createClient() 建立直连(非池化)连接,以支持迁移和会话级功能。完整示例请参阅 examples/core.md。
import { createPool } from "@vercel/postgres";
const pool = createPool({
connectionString: process.env.SECONDARY_POSTGRES_URL,
});
const { rows } =
await pool.sql`SELECT id, title FROM posts WHERE published = true`;
模式 4:边缘运行时注意事项
在边缘运行时中,SDK 会设置 maxUses: 1 —— 连接无法在请求之间重复使用。单次 sql 调用可正常运行;若要执行多个查询,请使用 sql.connect() 共享一个连接。边缘环境专用模式请参阅 examples/core.md。
模式 5:迁移到 @neondatabase/serverless
由于 @vercel/postgres 已弃用,请迁移到 @neondatabase/serverless。完整迁移示例请参阅 examples/core.md。
需要注意的主要差异:
@vercel/postgres返回{ rows, rowCount, ... };@neondatabase/serverless的neon()直接返回行(除非设置fullResults: true)@vercel/postgres会读取POSTGRES_URL;@neondatabase/serverless需要显式传入连接字符串(通常为DATABASE_URL)@neondatabase/serverless通过sql.transaction()支持 HTTP 事务和可组合片段
<decision_framework>
决策框架
选择哪个 API
What kind of operation?
+-- Single query (SELECT, INSERT, UPDATE, DELETE)
| +-- Use sql tagged template directly
+-- Multiple queries that must be atomic (transaction)?
| +-- Use sql.connect() to get a client, wrap in BEGIN/COMMIT
+-- Need custom connection string (not POSTGRES_URL)?
| +-- Use createPool() with explicit connectionString
+-- Need session-level features (SET, LISTEN/NOTIFY)?
| +-- Use createClient() (reads POSTGRES_URL_NON_POOLING)
+-- Starting a new project?
+-- Use @neondatabase/serverless instead
环境变量选择
What is the workload?
+-- Serverless/edge function --> POSTGRES_URL (pooled)
+-- Application queries --> POSTGRES_URL (pooled)
+-- Schema migrations --> POSTGRES_URL_NON_POOLING (direct)
+-- LISTEN/NOTIFY --> POSTGRES_URL_NON_POOLING (direct)
+-- pg_dump / pg_restore --> POSTGRES_URL_NON_POOLING (direct)
</decision_framework>
<red_flags>
危险信号
高优先级问题:
- 使用
sql处理事务,却没有使用sql.connect()——每次调用sql标记模板都可能使用不同的连接池连接。在一个连接上执行 BEGIN,在另一个连接上执行 COMMIT,意味着事务根本没有生效。 - 使用
sql.connect()后忘记调用client.release()——泄漏的客户端会耗尽连接池,导致后续所有查询一直挂起,直到超时。 - 将
POSTGRES_URL用于迁移——池化连接会通过事务模式的 PgBouncer 运行,这会导致迁移工具所需的会话级功能失效。
中优先级问题:
- 使用字符串插值而非标记模板——
sql`...${value}...`是安全的。sql.query(\...${value}...`)` 会导致 SQL 注入。 - 创建池或客户端后不关闭——
createClient()需要显式调用client.end()。忘记调用会导致连接泄漏。 - 忽略弃用信息——
@vercel/postgresv0.10.0 是最后一个版本,不会再发布安全补丁或错误修复。
易踩坑点和边缘情况:
- Edge 运行时中的
maxUses: 1——在 Edge 上,连接池无法在一次请求中重用连接。如果连续发起多次sql调用,每次都会新建一个连接。使用sql.connect()可共享一个连接。 sql是标记模板,不是函数——sql(...)是错误的。sql`...`才是正确写法。从非 Vercel Postgres 示例中复制代码时,这是一个常见错误。POSTGRES_URL与DATABASE_URL的区别——@vercel/postgres默认读取POSTGRES_URL。@neondatabase/serverless默认不读取任何变量(需显式传入)。迁移到 Neon 后,Vercel 会同时设置这两个变量,但代码必须符合 SDK 的预期。- PgBouncer 事务模式的限制——通过池化连接时,不支持 SET/RESET、LISTEN/NOTIFY、使用 PRESERVE 的临时表以及会话级咨询锁。
- 返回结果的结构与
@neondatabase/serverless不同——@vercel/postgres返回{ rows, rowCount, fields }。Neon 的neon()函数则直接返回行。如果迁移时没有考虑到这一点,代码就会出错。
</red_flags>
<critical_reminders>
重要提醒
所有代码都必须遵循项目在 CLAUDE.md 中的约定(kebab-case、命名导出、导入顺序、
import type、命名常量)
(一次性查询必须使用 sql 标记模板——它会自动从 POSTGRES_URL 建立连接并处理连接池)
(使用通过 sql.connect() 或 pool.connect() 获取的客户端后,必须调用 client.release()——泄漏的客户端会耗尽连接池)
(池化连接必须使用 POSTGRES_URL,直连必须使用 POSTGRES_URL_NON_POOLING——混用会导致连接耗尽或功能受限)
(必须说明 @vercel/postgres 已弃用——对于新项目,建议使用 @neondatabase/serverless)
不遵循这些规则会导致连接池耗尽、SQL 注入漏洞或事务静默失效。
</critical_reminders>