VoociiBlog
HomeBlogAI TrendingPortfolioBooksLinksToolsAbout
© 2026 Voocii. Built with Next.js & tRPC.
GitHubXEmailRSS


从 Neon 迁移到 Supabase:Next.js + Prisma 项目数据库平滑迁移

voocii-portalRickRickOctober 1, 2026·0 views

摘要:前天把本站的数据库从 从 Neon Serverless Postgres 迁移到 Supabase。本文简单总结了数据全量导出还原、双连接模式配置、Vercel 自动化部署,以及重点剖析了迁移过程中遇到的“连接池锁死”、“IPv6 连通性超时”等典型陷阱与解决方案。


1. 迁移背景与核心架构考量

在 Serverless 与全栈 Next.js 生态中,Neon 和 Supabase 都是极其优秀的托管 PostgreSQL 解决方案。迁移到 Supabase 通常能够获得更丰富的扩展生态(如内置的 Storage、向量检索 pgvector、实时订阅 Realtime 以及更灵活的数据库管理能力)。

然而,从 Neon 切换到 Supabase 并不是简单地替换一下 DATABASE_URL 就完事了。两者的网络架构与连接池设计存在本质不同:

维度Neon PostgreSQLSupabase
直连网络 (Direct Connection)默认原生提供公共 IPv4 支持默认仅支持 IPv6(IPv4 需每月 $4 购买 Add-on)
连接池 (Connection Pooler)按连接串配置透明路由代理提供独立的 Supavisor 连接池域名(支持 IPv4)
连接池端口与模式单一端口接入拆分双端口:6543(Transaction 事务模式)与 5432(Session 会话模式)
对 Prisma 迁移的影响单一连接串可同时跑查询与迁移必须区分应用查询(连接池)与数据迁移(直连/会话模式)

了解这一差异,是避免后续在 CI/CD 和生产环境部署踩坑的关键前提。


2. 完整迁移步骤

第一步:创建 Supabase 项目并获取连接信息

  1. 登录 Supabase Dashboard 并点击 New project。
  2. 选择 Region:建议选择离部署平台(如 Vercel)最近的节点(例如亚太区的新加坡 ap-southeast-1 或东京 ap-northeast-1)。
  3. 妥善保存创建项目时填写的 Database Password。
  4. 获取连接串:
    • 在新版 Supabase 后台,直接点击页面右上角的绿色 🔌 Connect 按钮。
    • 切换到 ORM 标签页,并选择 Prisma。
    • Supabase 会自动为你展示针对 Prisma 的两组连接串:
      • Connection Pooler (Transaction)(端口 6543)
      • Direct Connection / Session Pooler(端口 5432)

第二步:从 Neon 导出历史数据并导入 Supabase

如果线上有历史数据(如文章、评论、用户、系统配置),需要将原 Neon 中的数据完整迁移过来。

1. 从 Neon 备份导出(如已有备份可跳过)

pg_dump "postgresql://neondb_owner:password@ep-xxx.neon.tech/neondb?sslmode=require" \
  --clean --if-exists --no-owner --no-privileges -f neon_backup.sql

2. 将 SQL 文件导入 Supabase

使用标准的 psql 命令将导出的 .sql 文件导入到 Supabase 中:

# ⚠️ 注意:导入必须使用 5432 端口(Session Pooler 或 Direct),绝对不能使用 6543 端口
psql "postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:5432/postgres" -f neon_backup.sql

补充说明(如果是 .sql.gz 压缩备份文件):
如果生产环境定时备份的产物是 .sql.gz(例如 neon_backup_20260924_020001.sql.gz),无需先解压到本地磁盘,推荐利用终端管道流式解压并直接喂给 psql,高效且省空间:

gunzip -c neon_backup_20260924_020001.sql.gz | psql "postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:5432/postgres"

导入提示:

  • 导入过程中若出现 ERROR: role "neondb_owner" does not exist 或 ERROR: schema "public" already exists 提示,属于原 Neon 角色定义或默认 schema 重复声明,属于非致命错误,不影响表结构与数据导入。
  • 导入完成后,在 Supabase 后台左侧菜单的 Table Editor 中检查数据表和记录数是否完整。

第三步:调整项目 Prisma 与 Turborepo 配置

由于 Next.js 在 Serverless 下运行与 Prisma 命令行运行迁移时对连接的要求不同,需要配置 directUrl。

1. 修改 packages/db/prisma/schema.prisma

在 datasource 块中显式增加 directUrl:

datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")
  directUrl = env("DIRECT_URL")
}
  • url:给应用日常业务查询使用,指向 Supabase 连接池(端口 6543),防止 Serverless 高并发耗尽数据库连接。
  • directUrl:专门由 Prisma CLI(如 prisma migrate deploy / prisma db push)使用,指向会话模式(端口 5432),用于执行底层建表和会话咨询锁。

2. 更新 turbo.json 构建缓存感知

在根目录的 turbo.json 的 globalEnv 中添加 DIRECT_URL:

{
  "$schema": "https://turbo.build/schema.json",
  "globalEnv": [
    "DATABASE_URL",
    "DIRECT_URL",
    "AUTH_SECRET",
    ...
  ]
}

3. 配置本地开发环境 .env

若本地开发继续使用本地 Docker Postgres,可在 .env 中将 DIRECT_URL 设为与 DATABASE_URL 相同;若本地直连 Supabase 进行调试,填入对应的 Supabase 连接串即可:

# 运行时连接池 (Transaction Mode, 端口 6543)
DATABASE_URL="postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-ap-southeast-1.pooler.supabase.com:6543/postgres?pgbouncer=true"

# 迁移专用直连 (Session Mode, 端口 5432)
DIRECT_URL="postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-ap-southeast-1.pooler.supabase.com:5432/postgres"

第四步:在 Vercel 配置环境变量并重新部署

  1. 打开 Vercel 控制台 -> 对应项目 -> Settings -> Environment Variables。
  2. 更新或新增以下两个环境变量:
    • DATABASE_URL: postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:6543/postgres?pgbouncer=true
    • DIRECT_URL: postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:5432/postgres
  3. 确保同时勾选 Production、Preview 与 Development。
  4. 提交上述代码修改(schema.prisma 和 turbo.json),推送至远程仓库触发 Vercel 自动化部署(或在 Vercel 界面点击 Redeploy)。

3. 常见问题深度剖析与避坑指南 (Troubleshooting)

Q1:新版 Supabase 后台找不到 Project Settings -> Database -> Connection string?

原因:Supabase 近期更新了后台 UI,弱化了旧版深层菜单的入口。
解决方法:

  • 最快捷路径:在项目任意界面的右上角顶部栏,直接点击绿色的 🔌 Connect 按钮,弹窗中切换到 ORM -> Prisma 即可直接复制。
  • 菜单路径:点击左侧主导航从上往下第 4 个图标 Database -> 页面上方选择 Connection Pooling 亦可查看详细主机、端口与连接模式。

Q2:Vercel 部署卡在 prisma migrate deploy?是不是因为已有数据造成的?

现象:Vercel 构建日志一直挂起停留在 prisma migrate deploy,直至超时失败。许多开发者会怀疑是“导入了历史数据导致迁移冲突”,甚至考虑“是不是应该先在空库上构建部署,然后再导入数据”。

解答: 根本不是已有数据导致的!

  1. 如果数据库中已有数据(且已经包含 _prisma_migrations 表),Prisma 在执行 migrate deploy 时会校验迁移历史,发现所有迁移均已应用,会在 1 秒内输出 No pending migrations to apply 并正常退出。
  2. 如果存在表结构冲突,Prisma 也会立即抛出报错退出,而绝对不会长期“无响应挂起”。

真正导致卡死的原因有两个:

  1. 使用了 6543 端口的 Transaction Pooler 跑迁移:
    prisma migrate deploy 在执行时必须获取 PostgreSQL 的会话咨询锁(pg_advisory_lock)。6543 端口是事务连接池,不支持跨事务的咨询锁,导致 Prisma 一直等待锁释放而无限期挂死。
  2. 直连地址使用了 db.[PROJECT-REF].supabase.co 导致 IPv6 超时:
    Supabase 的默认直连域名只解析 IPv6 地址,而 Vercel 的构建容器机网络环境不支持 IPv6,导致 TCP 握手完全连不通,卡死直到超时。

正确解法: 配置 directUrl = env("DIRECT_URL"),并将 DIRECT_URL 指向 Session Pooler(域名是 aws-0-[REGION].pooler.supabase.com,端口为 5432)。此地址既支持 IPv4,又能正常获取迁移锁。


Q3:为什么之前用 Neon 时没有配置 directUrl,Vercel 却从来不卡?

原因:

  • 在 Neon 中,默认连接串(Host 不带 -pooler)是原生直连模式,且 Neon 默认原生提供免费的公共 IPv4 支持。
  • 因此在 Neon 下,一个连接串既能跑高并发业务查询,又具备 IPv4 连通性,还能正常获取 pg_advisory_lock,单靠 DATABASE_URL 即可满足全部需求。
  • 换到 Supabase 后,由于“直连默认仅 IPv6”以及“连接池分为了 6543/5432 两种模式”,必须通过 directUrl 进行动静分离。

Q4:项目中代码里并没有引用 DIRECT_URL,它是怎么起作用的?

解答: directUrl 是 Prisma 引擎的内建原生关键字。

  • 运行时业务代码(如 prisma.user.findMany()):Prisma Client 只会读取 url(即 DATABASE_URL),走 6543 事务连接池。
  • CLI 迁移命令(如 prisma migrate deploy、prisma migrate dev):Prisma 命令行检测到 schema.prisma 中声明了 directUrl 时,会自动切换使用 DIRECT_URL(5432 端口)。 业务代码层面完全无感知,无需做任何手动引用。

4. 后续维护建议

  1. 连接池容量监控: 在 Supabase 控制台的 Database -> Connection Pooling 中,可根据实际网站流量适当调整 Pool Size(默认连接池大小通常为 15,对中小型博客站点完全绰绰有余)。

Comments (0)

No comments yet. Be the first!

Leave a comment

On this page
  • 1. 迁移背景与核心架构考量
  • 2. 完整迁移步骤
  • 3. 常见问题深度剖析与避坑指南 (Troubleshooting)
  • 4. 后续维护建议