9.1 Edge 场景的特殊性
传统 Node.js 长进程:创建一个数据库连接池(e.g. 10 连接),全进程复用——创建一次、使用千万次。
Edge / Serverless 函数:每个请求可能启动全新实例,请求结束即销毁。如果每次都建 TCP 连接+TLS 握手+鉴权,延迟要 100-300ms,还把数据库的最大连接数打爆。
解决方案有两类:
- HTTP driver
- 把 SQL 通过 HTTP 请求发给专门的网关(Neon HTTP、Planetscale HTTP、Turso HTTP),不维持长连接——冷启动零开销。
- 连接池中间件
- PgBouncer、Supabase Supavisor、Neon pooler——应用侧维持短连接,网关端维持长连接池。
9.2 Neon Serverless(Postgres over WebSocket/HTTP)
$ npm i @neondatabase/serverless
import { drizzle } from "drizzle-orm/neon-http";
import { neon } from "@neondatabase/serverless";
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql);
Neon HTTP driver 把每个 SQL 发成一条 POST 请求,适合 Edge 函数、Cloudflare Workers、Vercel Edge Runtime。
若需要事务(HTTP 不能持 session),切到 WebSocket:
import { drizzle } from "drizzle-orm/neon-serverless";
import { Pool } from "@neondatabase/serverless";
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
export const db = drizzle(pool);
// 能用 db.transaction
9.3 Turso / libsql(分布式 SQLite)
Turso 是 LibSQL 的托管方案——分布式 SQLite 副本部署在全球边缘,HTTP + WebSocket 协议访问。
$ npm i @libsql/client
import { drizzle } from "drizzle-orm/libsql";
import { createClient } from "@libsql/client";
const client = createClient({
url: process.env.TURSO_DATABASE_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!,
});
export const db = drizzle(client);
本地开发也可以用 libsql(url: "file:local.db")——开发和生产共用一套 API。
9.4 Planetscale(HTTP MySQL)
$ npm i @planetscale/database
import { drizzle } from "drizzle-orm/planetscale-serverless";
import { Client } from "@planetscale/database";
const client = new Client({ url: process.env.DATABASE_URL });
export const db = drizzle(client);
Planetscale(Vitess 底层)不支持外键约束——schema 里 .references() 仍可以写(Drizzle 仅把它用于关系定义),但 migration 不生成 FOREIGN KEY 约束。业务层保证引用完整性。
9.5 Cloudflare D1
D1 是 Cloudflare Workers 原生的 SQLite——通过 env 绑定:
import { drizzle } from "drizzle-orm/d1";
type Env = { DB: D1Database };
export default {
async fetch(req: Request, env: Env) {
const db = drizzle(env.DB);
const users = await db.select().from(schema.users);
return Response.json(users);
},
};
wrangler.toml:
[[d1_databases]]
binding = "DB"
database_name = "my-db"
database_id = "xxxxx"
migrations_dir = "drizzle"
用 drizzle-kit 产出迁移,然后 wrangler d1 migrations apply DB 把它们推到 D1。
9.6 Vercel Postgres / Xata / Supabase
都提供自家 serverless driver:
@vercel/postgres+drizzle-orm/vercel-postgres@xata.io/client+drizzle-orm/xata-http- Supabase 推荐用 postgres-js + Supavisor pooler(如
db.xxx.pooler.supabase.co)
9.7 冷启动优化三要点
- Drizzle 本身 7KB——不占启动预算。
- driver 选 HTTP 优先——无 WebSocket/TCP 握手。
- schema 模块尽量小——导入整个
schema/*有成百列定义也不慢,但循环引用或大量 TypeScript 类型推断会拖编译。
9.8 环境变量与多环境
// .env
DATABASE_URL="postgresql://..."
NEON_ENV=dev
// drizzle.config.ts
export default defineConfig({
dialect: "postgresql",
schema: "./src/schema/*",
out: "./drizzle",
dbCredentials: { url: process.env.DATABASE_URL! },
});
9.9 本地开发 vs 生产
常见策略:本地跑 Postgres Docker 容器(和生产同方言),生产用 Neon/Supabase:
# docker-compose.yml
services:
db:
image: postgres:17
ports: ["5432:5432"]
environment:
POSTGRES_PASSWORD: pw
POSTGRES_DB: app
之后 DATABASE_URL="postgresql://postgres:pw@localhost:5432/app"——同一份 schema、同一份 migrate 代码。
9.10 小结
- Edge 环境:首选 HTTP driver(Neon/Turso/Planetscale/D1)——冷启动零开销。
- 事务需求用 WebSocket driver(Neon serverless Pool)。
- Planetscale 没外键,Cloudflare D1 通过绑定、Supabase 走 Supavisor pooler。
- 本地用 docker-compose 跑同方言库,和生产一致。