从Supabase迁移到Cloudflare D1,速度更快更省钱

1. 为什么迁移到Cloudflare?

之前NextJS项目从Vercel迁移到了CloudFlare,很重要的原因是Vercel 在使用量激增时容易产生高额账单,而 Cloudflare 则提供可预测、按使用量付费的模式。

虽然Vercel原生支持 Next.js 全栈功能,SSR/ISR 无缝运行;但Cloudflare 拥有 300+ 个全球节点,跑在全球边缘,响应延迟极低,而且配套完善。


2. 为什么从Supabase迁移到了CF D1?

当项目迁移到了Cloudflare之后,数据库连接的还是Supabase,但是随着项目的增多,Supabase free版本只支持两个project,更多的需要升级到Pro版本,需要$25/月。

那为什么不选择接入CF D1数据库呢?免费,而且与Cloudflare无缝集成,边缘场景下能避免额外网络开销。


3. 整体部署方案

先看一下当前整体的部署方案,项目为了部署到CF pages/workers上,需要使用OpenNext将NextJS生成物转化成CF平台上的。

  • workers是属于边缘运行时,缩短了和用户之间的延迟,同时为了提升运行速度,对node运行时做了精简。
  • OpenNext是个开源项目,为了让NextJs项目做到跨平台自托管,摆脱Vercel的限制。而OpenNext Cloudflare由CF团队运营,帮我解决这些维护和NextJS的更新适配问题。

4. 如何集成CF D1,适配开发和部署?

先看下面这个整体架构图

  • 这个架构解决了下面几个问题:

    1、 最重要的一点,NextJS项目开发,实时编译热加载,不影响开发效率

    2、本地worker环境调试本地D1数据库;

    3、NextJS项目转化成workers并部署;

    4、Cloudflare workers集成D1数据库;

这里需要指出的是:

1、使用OpenNext转化workers时,需要编译生成,花费时间比较多,无法做到实时编译。

2、其中DrizzleORM主要提供两方面功能,屏蔽底层不同的数据库的差异。

  • 针对数据库,提供统一的数据库连接和增删改查方式;
  • 针对数据表,将TS的对象转换成表结构的SQL

4.1 具体配置实现

  • 生产环境

D1数据库配置,具体内容根据自己项目配置

[[d1_databases]]
binding = "DB"
database_name = "***"
database_id = "***"
migrations_dir = "***"

D1数据库绑定

1export function db() { 2 if (isCloudflareWorker) { 3 // Cloudflare Workers 环境 4 const env = globalThis as any 5 if (!env.DB) { 6 throw new Error('D1 database binding not found') 7 } 8 return drizzle(env.DB) 9 } 10 11 return dbInstance 12}
  • 测试环境

配置本地数据库

1import 'dotenv/config' 2import { config } from 'dotenv' 3import { defineConfig } from 'drizzle-kit' 4 5config({ path: '.env' }) 6config({ path: '.env.development' }) 7config({ path: '.env.local' }) 8 9export default defineConfig({ 10 out: './src/db/migrations', 11 schema: './src/db/schema.ts', 12 dialect: 'sqlite', 13 dbCredentials: { 14 url: './.local.db', 15 }, 16})

本地数据库

1export function db() { 2 if (dbInstance) return dbInstance 3 const sqlite = new Database('./.local.db') 4 dbInstance = drizzleSqlite(sqlite) 5 6 return dbInstance 7}

vscode安装SQLite Viewer插件,直接打开.local.db可查询

4.2 相关命令

1# drizzle 相关 2npx drizzle-kit generate 3npx drizzle-kit migrate 4 5## 启动本地node环境 6pnpm dev 7 8## nextjs编译生成workers产物 9opennextjs-cloudflare build 10 11## 启动本地workers环境 12wrangler dev 13 14## 部署到线上cf workers 15opennextjs-cloudflare deploy 16

5. 其他失败的尝试

  • node环境+DrizzleORM API:

    本地node环境无法获取D1数据库绑定

  • node环境+DrizzleORM+ 自定义D1 adapter + D1 HTTP API:

    当存取数据的时候,数据返回错误,是个DrizzleORM和D1 HTTP API适配的已知BUG

  • node环境,通过openNext适配到workers环境,然后连接本地D1环境开发:

    每次改动代码都需要从NextJS到workers的环境,非常耗时