从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数据库绑定

export function db() {
  if (isCloudflareWorker) {
    // Cloudflare Workers 环境
    const env = globalThis as any;
    if (!env.DB) {
      throw new Error("D1 database binding not found");
    }
    return drizzle(env.DB);
  }

  return dbInstance;
}
  • 测试环境

配置本地数据库

import "dotenv/config";
import { config } from "dotenv";
import { defineConfig } from "drizzle-kit";

config({ path: ".env" });
config({ path: ".env.development" });
config({ path: ".env.local" });

export default defineConfig({
  out: "./src/db/migrations",
  schema: "./src/db/schema.ts",
  dialect: "sqlite",
  dbCredentials: {
    url: "./.local.db",
  },
});

本地数据库

export function db() {
  if (dbInstance) return dbInstance;
  const sqlite = new Database("./.local.db");
  dbInstance = drizzleSqlite(sqlite);

  return dbInstance;
}

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

4.2 相关命令

# drizzle 相关
npx drizzle-kit generate
npx drizzle-kit migrate

## 启动本地node环境
pnpm dev

## nextjs编译生成workers产物
opennextjs-cloudflare build

## 启动本地workers环境
wrangler dev

## 部署到线上cf workers
opennextjs-cloudflare deploy

5. 其他失败的尝试

  • node环境+DrizzleORM API:

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

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

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

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

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


Built with ShipFlare