摘要:前天把本站的数据库从 从 Neon Serverless Postgres 迁移到 Supabase。本文简单总结了数据全量导出还原、双连接模式配置、Vercel 自动化部署,以及重点剖析了迁移过程中遇到的“连接池锁死”、“IPv6 连通性超时”等典型陷阱与解决方案。
在 Serverless 与全栈 Next.js 生态中,Neon 和 Supabase 都是极其优秀的托管 PostgreSQL 解决方案。迁移到 Supabase 通常能够获得更丰富的扩展生态(如内置的 Storage、向量检索 pgvector、实时订阅 Realtime 以及更灵活的数据库管理能力)。
然而,从 Neon 切换到 Supabase 并不是简单地替换一下 DATABASE_URL 就完事了。两者的网络架构与连接池设计存在本质不同:
| 维度 | Neon PostgreSQL | Supabase |
|---|---|---|
| 直连网络 (Direct Connection) | 默认原生提供公共 IPv4 支持 | 默认仅支持 IPv6(IPv4 需每月 $4 购买 Add-on) |
| 连接池 (Connection Pooler) | 按连接串配置透明路由代理 | 提供独立的 Supavisor 连接池域名(支持 IPv4) |
| 连接池端口与模式 | 单一端口接入 | 拆分双端口:6543(Transaction 事务模式)与 5432(Session 会话模式) |
| 对 Prisma 迁移的影响 | 单一连接串可同时跑查询与迁移 | 必须区分应用查询(连接池)与数据迁移(直连/会话模式) |
了解这一差异,是避免后续在 CI/CD 和生产环境部署踩坑的关键前提。
ap-southeast-1 或东京 ap-northeast-1)。🔌 Connect 按钮。6543)5432)如果线上有历史数据(如文章、评论、用户、系统配置),需要将原 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
使用标准的 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 中检查数据表和记录数是否完整。
由于 Next.js 在 Serverless 下运行与 Prisma 命令行运行迁移时对连接的要求不同,需要配置 directUrl。
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),用于执行底层建表和会话咨询锁。turbo.json 构建缓存感知在根目录的 turbo.json 的 globalEnv 中添加 DIRECT_URL:
{
"$schema": "https://turbo.build/schema.json",
"globalEnv": [
"DATABASE_URL",
"DIRECT_URL",
"AUTH_SECRET",
...
]
}
.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"
DATABASE_URL:
postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:6543/postgres?pgbouncer=trueDIRECT_URL:
postgresql://postgres.[PROJECT-REF]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:5432/postgresProduction、Preview 与 Development。schema.prisma 和 turbo.json),推送至远程仓库触发 Vercel 自动化部署(或在 Vercel 界面点击 Redeploy)。Project Settings -> Database -> Connection string?原因:Supabase 近期更新了后台 UI,弱化了旧版深层菜单的入口。
解决方法:
🔌 Connect 按钮,弹窗中切换到 ORM -> Prisma 即可直接复制。Database -> 页面上方选择 Connection Pooling 亦可查看详细主机、端口与连接模式。prisma migrate deploy?是不是因为已有数据造成的?现象:Vercel 构建日志一直挂起停留在 prisma migrate deploy,直至超时失败。许多开发者会怀疑是“导入了历史数据导致迁移冲突”,甚至考虑“是不是应该先在空库上构建部署,然后再导入数据”。
解答: 根本不是已有数据导致的!
_prisma_migrations 表),Prisma 在执行 migrate deploy 时会校验迁移历史,发现所有迁移均已应用,会在 1 秒内输出 No pending migrations to apply 并正常退出。真正导致卡死的原因有两个:
prisma migrate deploy 在执行时必须获取 PostgreSQL 的会话咨询锁(pg_advisory_lock)。6543 端口是事务连接池,不支持跨事务的咨询锁,导致 Prisma 一直等待锁释放而无限期挂死。db.[PROJECT-REF].supabase.co 导致 IPv6 超时:正确解法:
配置 directUrl = env("DIRECT_URL"),并将 DIRECT_URL 指向 Session Pooler(域名是 aws-0-[REGION].pooler.supabase.com,端口为 5432)。此地址既支持 IPv4,又能正常获取迁移锁。
directUrl,Vercel 却从来不卡?原因:
-pooler)是原生直连模式,且 Neon 默认原生提供免费的公共 IPv4 支持。pg_advisory_lock,单靠 DATABASE_URL 即可满足全部需求。directUrl 进行动静分离。DIRECT_URL,它是怎么起作用的?解答:
directUrl 是 Prisma 引擎的内建原生关键字。
prisma.user.findMany()):Prisma Client 只会读取 url(即 DATABASE_URL),走 6543 事务连接池。prisma migrate deploy、prisma migrate dev):Prisma 命令行检测到 schema.prisma 中声明了 directUrl 时,会自动切换使用 DIRECT_URL(5432 端口)。
业务代码层面完全无感知,无需做任何手动引用。