Background
Next.js + Cloudflare 部署:生产环境使用 D1、本地开发使用 SQLite 的数据库方案

Next.js + Cloudflare 部署:生产环境使用 D1、本地开发使用 SQLite 的数据库方案

2026年2月1日2537 6分钟
Cayden
作者Cayden

独立开发者,做一些有趣的东西,在这里分享我的产品、技术经验和一些思考

欢迎关注微信公众号 CayDock

开发 W3Cay 项目时,我需要实现:生产环境使用 Cloudflare D1 数据库,本地开发使用 SQLite。这涉及 runtime 兼容性、构建配置、数据库连接管理等挑战。


技术选型

项目背景

W3Cay 是一个导航站项目,技术栈如下:

  • 前端框架:Next.js 15
  • 部署平台:Cloudflare Pages
  • 数据库:Cloudflare D1(生产)
  • 本地开发:SQLite

为什么没有用 Supabase

那为什么没有用 Supabase呢,主要是感觉 D1 和 CF 平台绑定更方便,而且给的量够多,基本用不完,我怕网站流量上来,Supabase 的免费额度顶不住,以下是一些对比

D1 vs Supabase

D1Supabase
延迟与 Pages 同网络,零延迟需回传中心数据库,有网络跳转
免费额度25,000 读/天,5GB 存储500MB 存储,500MB 传输
超出费用$0.001/千次读取$25/月起
部署与 Cloudflare 集成独立部署

本地开发为什么不用 D1?

wrangler pages dev 的开发体验差:

  1. 无热更新:修改后需重新构建(npm run cf:build && npm run cf:preview
  2. 调试困难:Edge Runtime 断点不如 Node.js 完善
  3. 流程繁琐:每次修改都要构建 → 预览 → 访问

如果使用本地 next dev + sqlite 就非常方便,基本上实时热更新看数据


那么下面我将总结下我如何做适配的

核心挑战

  • Edge Runtime:运行在 V8 Isolate,不支持 Node.js API
  • Node.js Runtime:支持完整 Node.js 生态

better-sqlite3 需要 Node.js 原生模块,只能在 Node.js Runtime 运行

而且 Next 项目中的服务渲染路由、API 都要声明 edge runtime 才能编译通过

不然会报错:

⚡️      Please make sure that all your non-static routes export the following edge runtime route segment config:
⚡️        export const runtime = 'edge';

这就是矛盾点,本地sqlite是基于 node 的本地读写API 实现的,如果使用 edge 环境,就使用不了,但 cloudflare 的编译必须要声明 edge


解决方案

管理 Edge Runtime 声明

首先解决本地的环境声明问题,默认本地使用node环境,编译 build 时使用 Edge Runtime

开发场景

新增运行环境注释标记 @CF_EDGE_RUNTIME

首先将代码中的 edge 声明都注释掉,通过 // @CF_EDGE_RUNTIME 来注释,这样给这一行一个标记,方便扫描处理,全部注释掉以后,这样我们本地开发就能直接使用sqlite了,不会出现报错

// src/app/api/random/route.ts
import { NextResponse } from 'next/server'
import { getDb, sites } from '@/db'

// @CF_EDGE_RUNTIME export const runtime = 'edge'

export async function GET() {
  const db = getDb()
  // ...
}

编译build场景

  1. 新增需要处理的页面路由或者api 清单文件,这个作为脚本处理的一个入口
// .edge-runtime-files.json
[
  "src/app/[locale]/page.js",
  "src/app/[locale]/site/[slug]/page.js",
  "src/app/api/random/route.js",
  "src/app/api/site/[abbr]/route.js"
]
  1. 新增构建脚本,新增两个脚本,作为编译前和编译后的钩子脚本
{
  "scripts": {
    "precf:build": "node scripts/manage-edge-runtime.js uncomment",
    "cf:build": "npm run content:full && npx @cloudflare/next-on-pages",
    "postcf:build": "node scripts/manage-edge-runtime.js comment"
  }
}

具体脚本代码我就不贴了,这个让 AI 直接写一个就行

  • precf:build:取消注释 Edge Runtime 声明
  • postcf:build:注释掉 Edge Runtime 声明
  1. sqlite3 动态导入问题

因为 sqlite3 依赖 node的 fs 等本地文件 api,如果直接 import better-sqlite3 等库,会导致开发时候就报错

使用 /* webpackIgnore: true */ 避免打包时分析模块,运行时动态加载:

const betterSqlite3Module = await import(/* webpackIgnore: true */ 'better-sqlite3')
const drizzleSqliteModule = await import(/* webpackIgnore: true */ 'drizzle-orm/better-sqlite3')

总结

实现效果

开发环境,本地 SQLite,零配置,热更新;编译时将 node 环境切换到 edge 环境,编译完成则恢复,生产上使用 CF 的 D1 数据库

关键要点

  1. Edge Runtime 管理:本地 Node,部署 Edge
  2. 动态导入/* webpackIgnore: true */ 避免打包问题
分享:

发表评论

最少 3 个字符您的邮箱不会被公开。标有 * 的字段为必填项(邮箱选填)

暂无评论。成为第一个分享想法的人吧!