首先: 请使用父级 neon 技能获取 Neon 概述、入门指南、开发最佳实践等更多信息。
如果未安装 neon 技能,请从 https://neon.com/docs/ai/skills/neon/SKILL.md 获取,或通过以下命令安装:
npx skills add neondatabase/agent-skills --skill neon
Neon Functions 是做什么的?
这是一个公共测试版功能,目前可在 us-east-2 和 eu-central-1 区域使用。
Neon Functions 是部署到 Neon 分支上的长运行时 Node.js HTTP 处理器。每个函数都有一个公共 HTTPS URL,与数据库运行在同一区域,并且——如果分支有 Postgres——会自动注入 DATABASE_URL。你可以通过已经熟悉的 Neon CLI、neon.ts 和 API 进行部署和管理。
使用此技能帮助用户定义、本地运行、部署和管理数据库旁边的函数。提供一个已部署的函数及其调用 URL、一个可工作的本地 neon dev 循环,或根据官方 Neon 文档提供精确的答案。
何时使用
当工作负载是受益于保持运行且靠近数据的请求/响应处理器时,请选择 Neon Functions:
- 超出 Lambda 风格限制的长运行请求/响应流程。 每个请求进行多次 LLM 调用和工具调用的 Agent,或图像/视频生成,通常会突破传统无服务器函数的约 10-60 秒执行上限和短流式传输窗口。Neon Functions 是长运行时的:处理器只需在 15 分钟内开始响应,只要字节持续流动,打开的流就会保持活跃。这足以应对真实的 Agent 工作负载。
- 无需借助 Redis 即可实现有状态流式传输。 因为函数在一个请求期间保持运行,它可以托管 SSE 端点或 WebSocket 服务器,并在进程内保持连接打开——无需外部状态存储(如 Redis)来维持流的一致性。模块作用域状态(如
pg连接池、内存计数器)在同一隔离区上的请求之间持续存在。 - 必须与 Postgres 相邻的计算。 该函数与分支的数据库运行在同一区域,因此每次查询无需跨区域往返。
DATABASE_URL会自动注入。 - 随数据一起分支的后端。 每个分支在其自己的 URL 上运行自己版本的函数,并拥有自己隔离的数据库(以及存储和网关)状态。预览部署、CI 和开发环境各自拥有一个自包含的后端——部署到子分支绝不会影响父分支。
- Webhook、机器人及请求后工作。 Webhook 处理器扇出到多个数据库写入、Discord/WebSocket 机器人,以及通过
waitUntil实现的一发即忘的后续操作(分析、审计日志),都适用。 - 周期性 HTTP 工作。 函数触发器按计划(
type: "schedule")向函数 POST 请求。使用相同的fetch处理器,相同的 15 分钟首次响应时间限制。参见函数触发器。
如果工作负载是纯静态站点,或者必须在当前支持的区域(us-east-2、eu-central-1)之外运行,那么这还不是合适的工具(参见超时和运行时限制和可用性)。
它能做什么
- 长运行时且无服务器 — 专为 WebSocket 服务器(参见 WebSocket 服务器)、SSE 端点(参见 服务器发送事件 (SSE))、长 Agent HTTP 流和 API 构建。空闲时仍会缩减到零。
- Web 标准处理器 — 函数是任何具有
fetch(request)方法并返回Response(兼容 Workers/WinterTC)的默认导出。Hono 应用正好是这种形状,因此export default app即可工作。运行在 Node.js 24 上,因此所有 Node API 都可用。 - 靠近你的数据库 — 在分支区域运行;当分支有 Postgres 时,
DATABASE_URL自动注入。 - 可分支 — 每个分支在其自己的 URL 上运行自己版本的函数,并拥有自己隔离的状态。
- 相同的 CLI/API — 通过
neon、neon.ts或 Neon API 进行部署和管理。 - 函数触发器 — Neon 按计划向函数 POST 请求。参见函数触发器。
可用性
在设置任何内容之前检查此先决条件:Neon Functions 是一个公共测试版功能,目前可在 us-east-2 和 eu-central-1 区域使用。确认用户的 Neon 项目位于这些区域之一。公共测试期间,函数使用不收费。
架构:函数的定位
Neon(包括 Functions)是后端原语,而非全栈应用托管。在 Vercel(或 Netlify,或其他前端/应用主机)上托管你的应用;Functions 是后端中长运行时、有状态的部分,位于数据旁边。它们以两种方式与你所在的平台组合:
- 将函数添加到全栈应用中。 你的 Next.js / TanStack Start 应用(在 Vercel 或 Netlify 上)拥有 UI、认证(例如 Neon Auth),并直接与 Lakebase Postgres 和对象存储通信。当一个工作负载超出主机的短无服务器限制时——比如 WebSocket 或 SSE 服务器,或一个会超时的长运行 Agent——只需将该部分移至 Neon Function。(参见将函数用作 Agent 后端了解客户端直连模式。)
- 在 Functions 上运行整个后端控制平面。 特别是当前端是纯客户端时——TanStack Router、客户端模式下的 React Router 以及类似 SPA(托管在 Vercel 或 Netlify 上)——客户端直接调用 Functions。构建 REST API 和请求/响应 Agent,托管 MCP 服务器,并运行任何有状态的或需要靠近 Postgres 和对象存储的内容。
无论哪种方式,都要像保护任何独立的 REST API 一样保护函数:在处理器顶部验证 JWT 或 API 密钥(请参见将函数用作 Agent 后端下的警告)。由于函数只是你的后端,你可以在主机和 Neon 之间移动片段——当 Agent 或有状态的 WebSocket 服务器需要更多运行时,将其迁移到 Function 上,并在需要时移回。
设置
函数在 neon.ts 中声明(有关分支优先工作流和 neon.ts 基础知识,请参见 neon 技能)。添加 @neon/config 并在 preview.functions 下声明函数,以slug 为键:
// neon.ts
import { defineConfig } from "@neon/config/v1";
export default defineConfig({
preview: {
functions: {
todos: {
// slug: ^[a-z0-9]{1,20}$ — 小写字母/数字,无连字符
name: "todo api", // 仅显示标签
source: "src/index.ts", // 入口文件,相对于 neon.ts
},
},
},
});
slug 是函数的永久标识(出现在调用 URL 和 CLI 命令中),首次部署后不能更改。使用 name 作为人类可读的标签。
最小函数——一个通过注入的 DATABASE_URL 查询分支 Postgres 的 Hono 应用:
// src/index.ts
import { Hono } from "hono";
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
import { parseEnv } from "@neon/env";
import { attachDatabasePool } from "@neon/functions";
import config from "../neon";
import { todos } from "./db/schema";
const env = parseEnv(config);
const pool = new Pool({ connectionString: env.postgres.databaseUrl, max: 5 });
attachDatabasePool(pool);
const db = drizzle(pool);
const app = new Hono();
app.get("/", (c) => c.text("Neon + Hono + Drizzle"));
app.post("/todos", async (c) => {
const { text } = await c.req.json<{ text: string }>();
const [row] = await db.insert(todos).values({ text }).returning();
return c.json(row, 201);
});
app.get("/todos", async (c) => c.json(await db.select().from(todos)));
export default app;
在模块作用域创建 pg 连接池(在同一隔离区的请求间重用),并保持 max 较小(例如 5),因为每个隔离区维护自己的连接池。调用 attachDatabasePool(pool) 以便空闲断开不会成为 uncaughtException——参见连接到 Postgres。
parseEnv(config) 要求配置文件暗示的_所有_变量。一个只通过连接池 URL 与 Postgres 通信的函数可以将其范围限定为该键——parseEnv 随后验证并仅返回你要求的内容(键名从你的 neon.ts 自动补全):
const { postgres } = parseEnv(config, ["DATABASE_URL"]); // 不包括非连接池 URL、认证等
const pool = new Pool({ connectionString: postgres.databaseUrl, max: 5 });
attachDatabasePool(pool);
本地开发与部署
neon dev # 服务 neon.ts 中的每个函数,带热重载;注入 DATABASE_URL 等
neon deploy --env <file> # 首选完整部署,基于 neon.ts;--env 是函数环境变量来源文件
保持 .env 或 .env.local 与 preview.functions.*.env 下的每个键同步。neon env pull 仅写入 Neon 管理的变量;将函数密钥添加到该文件中,然后将其作为 --env 传递。neon deploy --env <file> 每次将该文件加载到 process.env 中,然后上传这些值。缺失的值是 undefined,defineConfig 会抛出错误。如果你不想写入某个键,请从 neon.ts 中省略它。切勿将缺失的 process.env 值强制转换为空字符串(这会上传 "" 并删除实时密钥)。文件中的空赋值(KEY=)也是 ""。当 TypeScript 需要断言时,使用 process.env.X!。
要部署单个函数而不应用 neon.ts:neon functions deploy <slug> --src src/index.ts(--src 接受入口文件或包含 index.ts、index.mjs 或 index.js 的目录)。该命令的 --env 是 KEY=VALUE(可重复),不是文件路径。用于有针对性的环境更新。使用 neon functions get <slug> 检索公共 URL(invocation_url 字段,格式为 https://<branch_id>-<slug>.compute.<cell>.us-east-2.aws.neon.tech)。使用 neon functions list|get|delete 进行管理。
当 neon checkout _创建_新分支且存在 neon.ts 时,它会自动应用策略。此创建-应用不加载 --env。如果函数环境读取 process.env,请在 checkout 后运行 neon deploy --env <file>(如果 checkout 已创建分支,请添加 --update-existing)。checkout 现有分支不会重新部署;请显式运行 neon deploy --env <file>。
Neon 基础设施即代码 (neon.ts)
设置中的 preview.functions 块是 neon.ts(Neon 的基础设施即代码文件)的一部分——一个 TypeScript 文件声明了每个函数(其 source、显示 name 和 env),以及任何其他分支服务,并在版本控制中管理(有关完整参考,请参见 neon 技能)。像对待分支的 Terraform 一样对待它:
neon config status # 打印分支的实时配置(已部署的函数)
neon config plan # dry-run 差异,显示 apply 会更改什么
neon config apply --env <file> # 打包并部署声明的函数(neon deploy 是别名;当函数环境读取 process.env 时传递 --env)
函数是分支作用域的:每个分支在其自己的 URL 上运行自己的部署。当存在 neon.ts 时,neon checkout 在_创建_分支时应用策略。此创建-应用不加载 --env。如果函数环境读取 process.env,请在 checkout 后运行 neon deploy --env <file>。checkout _现有_分支不会重新部署——请运行 neon deploy --env <file> 以应用更改。
每个分支的部署调整(例如 runtime)位于 branch 闭包中,以 slug 为键,这样即使不更改存在哪些函数,也可以按分支变化:
export default defineConfig({
preview: {
functions: { todos: { name: "todo api", source: "src/index.ts" } },
},
branch: (branch) => ({
preview: { functions: { todos: { runtime: "nodejs24" } } },
}),
});
环境变量
Neon 在运行时注入分支作用域的连接字符串和服务 URL——你不需要声明这些或在部署时传递它们:
| 变量 | 注释 |
|---|---|
NEON_BRANCH | 分支名称(例如 main、preview/foo)。注入到每个分支,包括默认分支。 |
DATABASE_URL | 连接池连接字符串。用于大多数查询。仅当分支有 Postgres 时才存在。 |
DATABASE_URL_UNPOOLED | 直接连接。用于迁移、LISTEN/NOTIFY、多轮往返事务。 |
NEON_AUTH_BASE_URL | 当分支上启用 Neon Auth 时存在。 |
NEON_DATA_API_URL | 当分支上启用 Data API 时存在。 |
对象存储(AWS_*)和 AI Gateway(NEON_AI_GATEWAY_*)变量在声明这些服务时也会被注入——请参见 neon-object-storage 和 neon-ai-gateway 技能。
neon env pull / neon-env run / neon dev 也会将 NEON_BRANCH(以及连接字符串)输出到你的本地开发环境中,因此本地运行会镜像已部署的运行时。
你自己的密钥是每个部署的。推荐路径:在 neon.ts 中声明它们,然后运行 neon deploy --env <file>。<file> 是 env pull 已写入的 gitignore 文件(如果 .env 文件存在则使用它,否则使用 .env.local)。Env pull 仅写入 Neon 管理的变量;将函数密钥添加到该文件中。所有声明的函数环境键都必须存在。如果你不想写入某个键,请从 neon.ts 中省略它。undefined 意味着你要求写入该键但值缺失(defineConfig 会抛出错误)。切勿将缺失的 process.env 值强制转换为空字符串:这会上传 "" 并删除实时密钥。文件中的空赋值(KEY=)也是 ""。如果 TypeScript 需要断言,请使用 process.env.X!。
...
[内容截断,待翻译]