本地数据迁移到Supabase云数据库
11/25/2025, 3:24:12 PM
#Next.js#React#Node.js#Supabase
开发过程中因为需要,想将本地的 PostgreSQL 数据库的数据迁移到 Supabase 云数据库上面去,成功以后做了一份记录。
准备工作
1. 创建 Supabase 项目
- 访问 Supabase 官网,没有账号的话注册/登录;
- 准备好要迁移的项目,没有的话创建新项目;
- 复制数据库连接地址:类似于
postgresql://postgres:[密码]@db.[项目ID].supabase.co:5432/postgres
2.确保本地数据库正在运行
迁移步骤
步骤 1: 导出本地数据
写一个导出脚本:
/**
* 导出本地数据库所有数据到 JSON 文件
*/
import { PrismaClient } from '@prisma/client';
import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const prisma = new PrismaClient();
async function exportData() {
console.log('开始导出数据...\n');
try {
// 导出所有数据
const data = {
users: await prisma.user.findMany(),
// 这里依次写要导出的表
};
// 保存到文件
const exportDir = path.join(__dirname, '../../data-export');
await fs.mkdir(exportDir, { recursive: true });
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const exportFile = path.join(exportDir, `backup-${timestamp}.json`);
await fs.writeFile(exportFile, JSON.stringify(data, null, 2), 'utf-8');
console.log(`数据导出成功!`);
// 同时保存一个最新的备份(方便使用)
const latestFile = path.join(exportDir, 'latest-backup.json');
await fs.writeFile(latestFile, JSON.stringify(data, null, 2), 'utf-8');
console.log(`最新备份: ${latestFile}\n`);
return exportFile;
} catch (error) {
console.error('导出错误:', error);
throw error;
} finally {
await prisma.$disconnect();
}
}
// 执行导出
exportData()
.then(() => {
console.log('导出完成!');
process.exit(0);
})
.catch((error) => {
console.error('导出失败:', error);
process.exit(1);
});
运行导出脚本:
node scripts/tools/export-data.mjs
成功后会创建:
data-export/backup-[时间戳].json- 带时间戳的备份data-export/latest-backup.json- 最新备份(方便使用)
步骤 2: 在 Supabase 运行数据库迁移
-
临时切换到 Supabase 数据库
在
.env文件中,将DATABASE_URL改为 Supabase 连接字符串:# 注释掉本地数据库 # DATABASE_URL="postgresql://postgres:[密码]@localhost:5432/[项目名称]?schema=public" # 使用 Supabase 数据库 DATABASE_URL="postgresql://postgres:[密码]@db.[项目ID].supabase.co:5432/postgres"注意一下模式:
直连模式 (端口 5432) - 适合长连接
postgresql://postgres:[密码]@db.[项目ID].supabase.co:5432/postgres连接池模式 (端口 6543) - 适合短连接/无服务器
postgresql://postgres:[密码]@aws-0-[区域].pooler.supabase.com:6543/postgres迁移时使用直连模式,生产环境使用连接池模式。
-
运行 Prisma 迁移
npx prisma migrate deploy这会在 Supabase 数据库中创建所有表结构。
-
验证表结构
npx prisma studio打开 Prisma Studio 查看表是否正确创建(此时应该是空的)。
步骤 3: 导入数据到 Supabase
写一个导入脚本:
/**
* 将导出的数据导入到 Supabase 云数据库
*/
import { PrismaClient } from '@prisma/client';
import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const prisma = new PrismaClient();
async function importData(backupFile = null) {
console.log('开始导入数据到 Supabase...\n');
try {
// 确定要导入的文件
const exportDir = path.join(__dirname, '../../data-export');
const dataFile = backupFile || path.join(exportDir, 'latest-backup.json');
// 检查文件是否存在
try {
await fs.access(dataFile);
} catch {
console.error(`找不到数据文件: ${dataFile}`);
process.exit(1);
}
// 读取数据
console.log(`读取数据文件: ${dataFile}\n`);
const fileContent = await fs.readFile(dataFile, 'utf-8');
const data = JSON.parse(fileContent);
// 检查目标数据库是否为空(安全检查)
const existingData = {
users: await prisma.user.count(),
// 补充其它表数据
};
const totalExisting = Object.values(existingData).reduce((a, b) => a + b, 0);
if (totalExisting > 0) {
console.log('警告: 目标数据库已有数据,为防止数据冲突,导入已终止。如需强制导入,请先清空目标数据库或使用 --force 参数');
process.exit(1);
}
// 按顺序导入数据(注意考虑外键关系)
let imported = {
users: 0,
// 补充其它表数据
};
// 导入用户
if (data.users && data.users.length > 0) {
for (const user of data.users) {
try {
await prisma.user.create({ data: user });
imported.users++;
} catch (error) {
console.error(`导入用户失败 (${user.username}):`, error.message);
}
}
console.log(`已导入 ${imported.users}/${data.users.length} 个用户\n`);
}
// 还需要导入补充其它表数据
console.log('数据导入成功!\n');
} catch (error) {
console.error('导入数据时发生错误:', error);
throw error;
} finally {
await prisma.$disconnect();
}
}
// 解析命令行参数
const args = process.argv.slice(2);
const backupFile = args.find((arg) => !arg.startsWith('--'));
// 执行导入
importData(backupFile)
.then(() => {
console.log('导入完成!');
process.exit(0);
})
.catch((error) => {
console.error('导入失败:', error);
process.exit(1);
});
运行导入脚本:
node scripts/tools/import-data.mjs
如果需要指定特定的备份文件:
node scripts/tools/import-data.mjs data-export/backup-2025-11-20T12-30-00-000Z.json
注意脚本引入了安全机制,防止覆盖现有数据,如果目标数据库已有数据会终止导入,解决方法:
-
清空 Supabase 数据库(如果确定要重新导入):
npx prisma migrate reset --force -
或者手动删除所有记录(在 Supabase 控制台)
如果只想导部分数据,那就编辑 data-export/latest-backup.json 文件,删除不需要的记录,然后再运行导入脚本。
步骤 4: 验证数据
-
使用 Prisma Studio 验证
npx prisma studio检查所有数据是否正确导入。
-
在 Supabase 控制台验证
- 访问 Supabase 控制台
- 进入 Table Editor
- 检查各个表的数据
-
测试应用
npm run dev
回滚到本地数据库
如果需要回到本地数据库:
-
在
.env中恢复本地连接:DATABASE_URL="postgresql://postgres:[密码]@localhost:5432/[项目名称]?schema=public" -
重启应用:
npm run dev
官方文档参考 :