数据库
在 Netlify 上用…
当 Netlify 应用需要数据库(增删改查、contact form、CRUD API)、要写 SQL 迁移、接 Drizzle ORM、用 netlify dev 本地调试、给 deploy preview 建数据库分支,或把现有 Postgres 项目迁到 Netlify Database 时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Netlify 上用 @netlif特定
解决思路
- 安装 @netlify/database,在 netlify/database/migrations/ 下写迁移文件,然后部署——Netlify 会自动 provision 数据库并应用迁移;Function、Edge Function、Build、Agent Runner 中都可查询。
- 查询优先用现代客户端:import { getDatabase } from "@netlify/database",const db = getDatabase() 会自动为当前运行时选择连接,用 await db.sql`SELECT * FROM users WHERE id = ${userId}` 这类模板查询(自动参数化)。
- 自带 driver/ORM 时用 getConnectionString():import { getConnectionString } from "@netlify/database",const connectionString = getConnectionString() 拿到当前环境正确分支的连接串。
- 新代码不要用 legacy 的 @netlify/neon 的 neon();把 neon() 调用替换为 Drizzle 的 netlify-db adapter 或经 getConnectionString() 的 Postgres driver;legacy 环境变量 NETLIFY_DATABASE_URL 换成 NETLIFY_DB_URL。
- 按约定放文件:迁移 → netlify/database/migrations/;查询代码 → Functions(netlify/functions/)与 Edge Functions;Drizzle schema → db/schema.ts;Drizzle client → db/index.ts;连接串 → NETLIFY_DB_URL 环境变量或 getConnectionString()。
- getDatabase(options?) 返回带 sql 和 pool 的客户端;options.connectionString 可覆盖自动 provision 的连接串,options.debug 开启日志。
- 用模板标签做增删改查:db.sql`INSERT INTO users (name, email) VALUES (${...}, ${...})`、UPDATE、DELETE,所有值都走 ${} 占位以自动参数化。
- 给结果行加类型:先定义 interface User,再用 const typed = await db.sql<User>`SELECT * FROM users`。
- 大数据量用流式读取:for await (const row of db.sql`SELECT * FROM users`.stream()),或 for await (const chunk of db.sql`SELECT * FROM users`.chunked(100))。
- SQLTemplate 方法:execute() → Promise<T[]>;stream() → AsyncGenerator<T>;chunked(n) → AsyncGenerator<T[]>;toSQL() → 返回原始 SQL + 参数但不执行。
- sql helpers:sql.identifier(value) 安全引用表/列名(支持 string、string[]、{ schema, table, column, as });sql.values(rows) 由二维数组生成批量插入值列表;sql.default 表示 SQL 的 DEFAULT。
- sql.raw(value) 会注入未参数化 SQL、绕过注入保护——只用于可信常量(如 DESC),绝不用用户输入。
- sql.unsafe(query, params?, { rowMode }) 用于原始查询串 + $1 参数,rowMode 取 array 或 object。
- 事务必须用 db.pool(即 pg.Pool):const client = await db.pool.connect(),在同一个 client 上依次执行 BEGIN / 查询 / COMMIT;出错时 ROLLBACK 后 rethrow;最后 client.release()。
- 自己接 driver:new pg.Pool({ connectionString: getConnectionString() }),或 import postgres from "postgres"; const sql = postgres(process.env.NETLIFY_DB_URL)。
- 用 Drizzle 时必须从 @beta 安装:npm install @netlify/database drizzle-orm@beta 与 npm install -D drizzle-kit@beta;latest 没有 drizzle-orm/netlify-db adapter,会直接失败。
- drizzle.config.ts 必须把 out 设为 netlify/database/migrations(不是默认的 drizzle),否则 Netlify 不会应用生成的迁移;dialect 用 postgresql,schema 指向 ./db/schema.ts。
- 用 db/schema.ts + pgTable 定义表,例如 serial().primaryKey()、text().notNull().unique()、timestamp().defaultNow()。
- db/index.ts 写 import { drizzle } from "drizzle-orm/netlify-db"; import * as schema from "./schema"; export const db = drizzle({ schema });(原生 adapter,自动配置)。
- 在 Function 中用 Drizzle:db.select().from(users).orderBy(desc(users.createdAt))、db.insert(users).values({...}).returning(),并用 export const config: Config = { path: "/api/users" } 绑定路径。
- 改完 schema 跑 npx drizzle-kit generate 生成迁移文件;永远不要对 Netlify 托管的数据库跑 drizzle-kit push,也不要对 NETLIFY_DB_URL 跑 drizzle-kit migrate——schema 只能以提交的迁移文件由部署应用。
- 迁移文件支持两种格式:netlify/database/migrations/20260301143000_create_users.sql 单文件,或 netlify/database/migrations/20260318091500_add_posts/migration.sql 子目录形式。
- 迁移命名用 <number>_<slug>:number 为数字(时间戳或 0001…)决定顺序,slug 为小写字母/数字/连字符/下划线;按字典序排序应用;用时间戳前缀(netlify database migrations new 会自动处理)避免 out-of-order 被拒。
- 迁移应用时机:生产部署在 publish 前立即应用,失败会阻断 publish(关闭 auto-publish 时等手动 publish 前应用);deploy preview 每次部署上线前应用,失败则部署失败;本地不会自动应用,需自己跑 netlify database migrations apply。
- 迁移禁令:不要编辑已应用迁移(会 checksum drift,报 migration "<name>" has been modified after being applied),要写新的纠正迁移;不要删除已应用迁移(会被判定为已应用后移除),需恢复;不要 out-of-order(前缀 ≤ 最高已应用版本会被拒)。
- 优先写向后兼容的迁移;破坏性变更(重命名/删除列)用 expand-and-contract 跨多次部署完成;新表/可空列单次迁移即可。
- 自带迁移系统时,选 netlify/database/migrations 以外的目录以免被自动检测,并自行负责应用到 preview 分支和生产。
- 本地开发只有一个数据库,所有代码都指向它;分支是部署时概念,本地不存在;本地是镜像生产的真实 Postgres 兼容引擎,但单进程(不要用于压测),auto-scale/sleep 设置不适用。
- 启动本地数据库:跑 netlify dev(CLI 会启动并自动拆除本地 DB),或在 vite.config.ts 里 import netlify from "@netlify/vite-plugin" 并加 plugins: [netlify()];两条路径状态互通。
- 本地常用命令:netlify database migrations apply(应用待执行迁移)、netlify database migrations new -d "add users table"(脚手架新迁移)、netlify database migrations pull(用远端覆盖本地迁移)、netlify database status(是否启用/已安装/已应用与待执行迁移)、netlify database connect(交互式 SQL REPL)、netlify database connect --query "SELECT * FROM users LIMIT 10"、netlify database reset(丢弃所有 schema/表,仅本地)、netlify database migrations reset(删除未应用的本地迁移文件)。
- 接外部工具(netlify dev 运行期间):psql "$(netlify database connect --json | jq -r .connection_string)"。
- 新项目初始化:在 https://app.netlify.com/start 向 Agent Runners 描述应用,或本地跑 netlify create "<description>"。
- 已有项目初始化:跑 netlify database init(安装 @netlify/database、选择 Drizzle 或 raw SQL、脚手架一个迁移),CI/agent 里用 netlify database init --yes 非交互,然后 netlify dev;手动路径是 npm install @netlify/database + 写迁移 + 写 function + netlify dev + 部署。
- 记住:未安装 @netlify/database 时 Netlify 不会自动 provision 数据库,只能在 UI 的 Data & Storage > Database 菜单手动创建;所以先安装包。
- CLI 前置:Node ≥ 20.12.2、Netlify CLI ≥ 26.0.0(npm install -g netlify-cli);所有命令支持 --json。
- netlify database 子命令与关键 flags:init(-y, --yes);status(-b, --branch、--show-credentials);connect(-q, --query、--json);migrations apply(--to <name>);migrations new(-d, --description、-s, --scheme sequential|timestamp);migrations pull(-b, --branch、--force);migrations reset(-b, --branch);reset(仅本地)。
- 走 REST API 时:站点作用域,根地址 https://api.netlify.com/api/v1,OAuth 2;POST /sites/{site_id}/database 创建 DB(已存在则返回现有连接串,可选 region),GET /sites/{site_id}/database 取连接串。
- 分支与快照 REST:POST /sites/{site_id}/database/branch(body deploy_id 必填、parent_branch_id 可选默认生产)、GET /sites/{site_id}/database/branch/{deploy_id}、DELETE /sites/{site_id}/database/branch/{deploy_id}、POST /sites/{site_id}/database/snapshot、GET /sites/{site_id}/database/snapshots、DELETE /sites/{site_id}/database/snapshot/{snapshot_id}、POST /sites/{site_id}/database/snapshot/{snapshot_id}/restore。
- 分支删除与快照恢复是破坏性操作,必须先获得用户明确确认;不要把快照恢复当成常规的生产回滚手段。
- 单测/集成测试用裸 Postgres:npm i -D @netlify/database-dev,new NetlifyDB(),在 beforeAll 中 await db.start() 并 await db.applyMigrations("./netlify/database/migrations"),在 afterAll 中 await db.stop();NetlifyDB 选项有 directory(持久化到磁盘,不填则内存)、port(默认随机)、logger。
- 测试需要完整 Netlify 环境(functions/edge functions 像生产一样读 NETLIFY_DB_URL)时,用 npm i -D @netlify/dev 的 new NetlifyDev({ projectRoot: "./fixtures/my-project" }),await netlifyDev.start() 后跑测试,最后 await netlifyDev.stop()。
- 依赖数据库分支行为:只有生产部署会碰生产数据库;每个 deploy preview 自动获得独立分支,并在 preview 创建时用生产数据副本 seed;其 schema/数据变更不影响生产;已自动接线,无需改代码。
- 分享 preview 部署链接前先警告用户:preview 分支可能含生产数据(包括 PII),而 preview 链接是公开的。
- 遇到 Environment not configured(getDatabase() 无法解析连接串)时显式传连接串:getDatabase({ connectionString: "postgres://..." });常见原因是运行在 Netlify 之外、Functions 处于 Lambda compatibility mode、或 CLI 过旧;Lambda compatibility mode 是唯一必须自己传 connectionString 的原语。
- 其它错误对照处理:database feature not available for this account → 需要 Credit-based plan;compute customization requires a Pro or higher plan → auto-scale/sleep 需 Pro+;branch limit reached: maximum <N> branches... → 每个活跃 deploy preview 占一个分支,删除不需要的分支或升级;database not found → 跑 netlify database init;cannot reset the production branch → reset 仅限非生产。
- 计划与配额:Netlify Database 仅在 Credit-based plan 可用,活跃 DB 会消耗 compute 与 bandwidth 的 credits,存储在 2026-07-01 前免费。
- 权限:只有 Team Owner 能删除数据库;只有 Team Owner 和 Developers 能查看连接串(Access Denied 表示角色不够)。
- 密钥:连接串含用户名 + 密码,绝不提交;存到 secret manager / 环境变量提供方。
- 从现有 Postgres(Neon、Supabase、RDS、自管、legacy @netlify/neon)迁到 Netlify Database 分三阶段:provision(在分支上建 baseline schema)、rehearse(换代码、把数据拷进 preview 分支、验证)、cut over(把数据导入生产、合并);用与源版本匹配的 pg_dump/pg_restore;注意最终导出到生产部署之间的写入不会同步,存在短暂数据丢失窗口。
- 迁移时的代码替换(Drizzle):db/index.ts 改为 import { drizzle } from "drizzle-orm/netlify-db"; import * as schema from "./schema"; export const db = drizzle({ schema });。
- 生产数据变更以 DML 迁移表达,agent 绝不直接编辑行(UI 行编辑是给人用的,不是 agent 界面)。
- 只用文档化 surface:不对内部端点跑裸 psql,不用 netlify api 抓取,不从本地 CLI 配置文件读 token。
- 细节查本技能的 references:references/operational-footguns.md、references/migrations.md、references/local-dev.md、references/cli-commands.md、references/migration-from-extension.md、references/legacy-extension.md。
- schema 变更只能以提交的迁移文件由部署应用到托管数据库;永不对 Netlify 托管数据库跑任何形式的 drizzle-kit push,永不对 NETLIFY_DB_URL 跑 drizzle-kit migrate,永不通过 netlify database connect 或任何直接连接执行 DDL。
- 当 netlify 命令或部署失败时,把确切错误、deploy log URL、受影响的 site/branch 交给用户并停止,不要自创恢复命令或降级到更低级工具。
- 首次部署 createSiteDatabase 报 401 Access Denied 时:若发生在 --prod-first 部署,改成 preview-first 重试(netlify deploy,不带 --prod);若 preview 也失败,报告并停止;绝不要 curl api.netlify.com、跑 netlify api createSiteDatabase 或从本地 CLI 配置拉 token 绕过。
- 修改现有数据的请求在生产与 preview 分支之间有歧义——prompt 没说清就先问;代他人操作时默认不碰生产。
- 破坏性数据库操作(REST 分支删除、快照恢复、任何 reset)必须先获得明确用户确认。
- 固定版本:drizzle-orm 与 drizzle-kit 必须从 @beta 安装,latest 缺 drizzle-orm/netlify-db adapter 会失败。
- 分支删除与快照恢复的确认流程:先把影响面(site、branch、snapshot)说清楚再等用户确认,确认后才调用对应 REST 端点。
适用边界 · 注意事项
- 项目不在 Netlify 上托管,或坚持用其他 Postgres 提供商(Neon/Supabase/RDS/自管)且不打算迁移。
- 账户不是 Credit-based plan(数据库功能不可用),或只能用免费/自托管 Postgres。
- 需要 drizzle-kit push 式即时把 schema 同步到数据库、或要直接对托管库执行 DDL/直接改生产数据行的场景。