Skip to content
Platform

从 Postgres 迁移到 Supabase

Migrate your existing Postgres database to Supabase.

这是一个将你的 Postgres 数据库迁移到 Supabase 的指南。Supabase 是一个强大且开源的平台。Supabase 提供开发者构建产品所需的所有后端功能:Postgres 数据库、身份验证、即时 API、边缘函数、实时订阅和存储。Postgres 是 Supabase 的核心——例如,你可以使用行级安全,而且还有超过 40 个可用的 Postgres 扩展。

🌐 This is a guide for migrating your Postgres database to Supabase. Supabase is a robust and open-source platform. Supabase provides all the backend features developers need to build a product: a Postgres database, authentication, instant APIs, edge functions, real-time subscriptions, and storage. Postgres is the core of Supabase—for example, you can use row-level security, and there are more than 40 Postgres extensions available.

本指南演示了如何将你的 Postgres 数据库迁移到 Supabase,让你在充分利用 Postgres 的同时,还能获得构建项目所需的所有功能。

🌐 This guide demonstrates how to migrate your Postgres database to Supabase to get the most out of Postgres while gaining access to all the features you need to build a project.

本指南提供三种将你的 Postgres 数据库迁移到 Supabase 的方法:

🌐 This guide provides three methods for migrating your Postgres database to Supabase:

  1. Google Colab - 带有复制粘贴工作流程的指导注意本
  2. 手动导出/恢复 - 命令行方式,适用于所有版本
  3. 逻辑复制 - 最小停机时间,需要 Postgres 10+

连接模式 #

🌐 Connection modes

Supabase 提供以下连接模式:

🌐 Supabase provides the following connection modes:

  • 直接连接
  • Supavisor 会话模式
  • Supavisor 交易模式

在数据库迁移任务(pg_dump/恢复和逻辑复制)中使用 Supavisor 会话模式。

🌐 Use Supavisor session mode for the database migration tasks (pg_dump/restore and logical replication).

方法1:谷歌Colab(最简单) #

🌐 Method 1: Google Colab (easiest)

Supabase 提供了一个 Google Colab 迁移注意本,让迁移过程更有指导性: Supabase 迁移 Colab 注意本

🌐 Supabase provides a Google Colab migration notebook for a guided migration experience: Supabase Migration Colab Notebook

如果你喜欢逐步、复制粘贴的工作流程,而且设置很少的话,这就很理想。

🌐 This is ideal if you prefer a step-by-step, copy-paste workflow with minimal setup.

方法二:手动导出/恢复 #

🌐 Method 2: Manual dump/restore

这种方法适用于所有使用命令行工具的 Postgres 版本。

🌐 This method works for all Postgres versions using CLI tools.

先决条件 #

🌐 Prerequisites

源 Postgres 要求 #

🌐 Source Postgres requirements

  • 拥有运行 pg_dump 权限的连接字符串
  • 转储/恢复不需要特殊设置
  • 来自迁移虚拟机的网络访问

迁移环境 #

🌐 Migration environment

  • 与源数据库或目标数据库在同一地区运行的 Ubuntu 云虚拟机
  • 与你的源数据库版本匹配的 Postgres 客户端工具
  • tmux 用于会话持久化
  • 足够的磁盘空间(通常大约是源数据库大小的50%就够了,但具体情况会有所不同)

迁移前清单 #

🌐 Pre-Migration checklist

1
-- Check database size
2
select pg_size_pretty(pg_database_size(current_database())) as size;
3
4
-- Check Postgres version
5
select version();
6
7
-- List installed extensions
8
select * from pg_extension order by extname;
9
10
-- Check active connections
11
select count(*) from pg_stat_activity;

查看 Supabase 中可用的扩展 #

🌐 Check available extensions in Supabase

1
-- Connect to your Supabase database and check available extensions
2
SELECT name, comment FROM pg_available_extensions ORDER BY name;
3
4
-- Compare with source database extensions
5
SELECT extname FROM pg_extension ORDER BY extname;
6
7
-- Install needed extensions
8
CREATE EXTENSION IF NOT EXISTS extension_name;

第1步:设置迁移虚拟机 #

🌐 Step 1: Set up migration VM

设置 Ubuntu 虚拟机 #

🌐 Set up Ubuntu VM

1
# Install Postgres client and tools
2
sudo apt update
3
sudo apt install software-properties-common
4
sudo sh -c 'echo "deb http://apt.Postgres.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
5
wget --quiet -O - https://www.Postgres.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
6
sudo apt update
7
sudo apt install Postgres-client-17 tmux htop iotop moreutils
8
9
# Start or attach to tmux session
10
tmux a -t migration || tmux new -s migration

第2步:准备 Supabase 项目 #

🌐 Step 2: Prepare Supabase project

  1. supabase.com/dashboard 创建一个 Supabase 项目
  2. 记下你的数据库密码
  3. 通过 SQL 或仪表板安装所需的扩展
  4. 获取你的连接字符串:
    • 项目 → 设置 → 数据库 → 连接池
    • 选择 会话池(端口 5432)并复制连接字符串
    • 连接格式:Postgres://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres

重要注意事项

  • 用户/角色不会被迁移 - 导入后你需要重新创建角色和权限 (Supabase 角色指南)
  • 表的行级安全性 (RLS) 状态未迁移 - 迁移后你需要为表启用 RLS。

资源需求

数据库大小推荐计算资源推荐虚拟机需要的操作
< 10 GBDefault2 vCPUs, 4 GB RAMNone
10-100 GBDefault-Small4 vCPUs, 8 GB RAMConsider compute upgrade
100-500 GBLarge compute8 vCPUs, 16 GB RAM, NVMeUpgrade compute before restore
500 GB - 1 TBXL compute16 vCPUs, 32 GB RAM, NVMeUpgrade compute before restore
> 1 TB自定义自定义联系支持

另外,如果你想要更快地恢复数据库,你可以通过 设置 → 计算和磁盘 临时增加计算资源和/或磁盘 IOPS 及吞吐量(如果这样做,你可以在 pg_restore 中使用更大的 -j)。

🌐 Also, you can temporarily increase compute size and/or disk IOPS and throughput via Settings → Compute and Disk if you want faster database restore (you can use larger -j for pg_restore if you do so).

步骤 3:创建数据库转储 #

🌐 Step 3: Create database dump

将源数据库设置为只读模式以进行生产迁移 #

🌐 Set source database to read only mode for production migration

如果在进行维护窗口迁移,请防止数据更改:

🌐 If doing a maintenance window migration, prevent data changes:

1
-- Connect to source database and run:
2
ALTER DATABASE your_database_name SET default_transaction_read_only = true;

如果没有维护时间进行测试,可以跳过这一步,但使用较低的 -j 值。

🌐 For testing without a maintenance window, skip this step but use lower -j values.

导出数据库 #

🌐 Dump the database

1
# Determine number of parallel jobs based on:
2
# - Source database CPU cores (don't saturate production)
3
# - VM CPU cores
4
# - For testing without maintenance window: use lower values to be gentle
5
# - For production with maintenance window: can use higher values
6
7
DUMP_JOBS=4 # Adjust based on your setup
8
9
# Check available cores on VM
10
nproc
11
12
# Create dump with progress logging
13
pg_dump \
14
--host=<source_host> \
15
--port=<source_port> \
16
--username=<source_username> \
17
--dbname=<source_database> \
18
--jobs=$DUMP_JOBS \
19
--format=directory \
20
--no-owner \
21
--no-privileges \
22
--no-subscriptions \
23
--verbose \
24
--file=./db_dump 2>&1 | ts | tee -a dump.log

关于转储标志的说明

  • --no-owner --no-privileges:在导出时应用以防止 Supabase 用户管理冲突。虽然这些也可以在 pg_restore 中使用,但在导出时应用可以让导出文件更干净、更易移植。
  • --no-subscriptions:逻辑复制订阅在目标端无法使用
  • 这个转储会捕获所有数据和架构,但不包括可能与 Supabase 管理环境冲突的所有权/权限
  • 如果只想迁移一个数据库模式,在你的 pg_dump 命令中添加 --schema=PATTERN 参数。
  • 要排除一个模式:--exclude-schema=PATTERN
  • 只迁移一个表:--table=PATTERN
  • 要排除一个表:--exclude-table=PATTERN

运行 pg_dump --help 查看完整选项列表。

🌐 Run pg_dump --help for a full list of options.

🌐 Recommended parallelization (-j values)

数据库大小测试环境(无维护窗口)生产环境(有维护窗口)限制因素
< 10 GB24源端 CPU
10-100 GB2-48源端 CPU
100-500 GB416磁盘 IOPS
500 GB - 1 TB4-816-32磁盘 IOPS + CPU

注意:如果在没有维护窗口的情况下进行测试,请使用较低的 -j 值,以避免影响生产性能。

第4步:恢复到Supabase #

🌐 Step 4: Restore to Supabase

设置连接并恢复 #

🌐 Set connection and restore

1
# Set Supabase connection (Session Pooler on port 5432 or direct connection)
2
export SUPABASE_DB_URL="Postgres://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres"
3
4
# Determine restore parallelization based on your Supabase compute size:
5
# Free tier: 2 cores → use -j 2
6
# Small compute: 2 cores → use -j 2
7
# Medium compute: 4 cores → use -j 4
8
# Large compute: 8 cores → use -j 8
9
# XL compute: 16 cores → use -j 16
10
11
RESTORE_JOBS=8 # Adjust based on your Supabase compute size
12
13
# Restore the dump (parallel mode)
14
# Note: -j cannot be used with --single-transaction
15
pg_restore \
16
--dbname="$SUPABASE_DB_URL" \
17
--jobs=$RESTORE_JOBS \
18
--format=directory \
19
--no-owner \
20
--no-privileges \
21
--verbose \
22
./db_dump 2>&1 | ts | tee -a restore.log

如果恢复失败并出现扩展错误,检查错误是否仅与扩展相关。

🌐 If restore fails with extension errors, check that errors are only extension-related.

第5步:迁移后的任务 #

🌐 Step 5: Post-Migration tasks

更新统计数据(重要) #

🌐 Update statistics (important)

1
psql "$SUPABASE_DB_URL" -c "VACUUM VERBOSE ANALYZE;"

验证迁移 #

🌐 Verify migration

1
-- Check row counts
2
select schemaname, tablename, n_live_tup
3
from pg_stat_user_tables
4
order by n_live_tup desc
5
limit 20;
6
-- Verify data with application-specific queries

重新启用源上的写入(如果要保留的话) #

🌐 Re-enable writes on source (if keeping it)

1
ALTER DATABASE your_database_name SET default_transaction_read_only = false;

迁移时间估计 #

🌐 Migration time estimates

数据库大小导出时间恢复时间总时间
10 GB约5分钟约10分钟约15分钟
100 GB约30分钟约45分钟约1.5小时
500 GB约2小时约3小时约5小时
1 TB约4小时约6小时约10小时

时间会根据硬件、网络和并行设置而变化

🌐 Times vary based on hardware, network, and parallelization settings

重要提示 #

🌐 Important notes

  1. 区域接近很重要:虚拟机应与源或目标位于同一区域,以获得最佳性能
  2. 降级迁移:虽然在某些情况下技术上可行,但强烈不推荐
  3. 无停机测试:使用较低的 -j 值进行 pg_dump,以避免影响生产环境
  4. 对于 pg_restore:可以使用完全并行化,不管对生产的影响
  5. 监控资源:使用 htopiotop 观察 CPU、磁盘 I/O
  6. 磁盘 I/O:通常是在网络带宽之前的瓶颈

方法3:逻辑复制 #

🌐 Method 3: Logical replication

这种方法利用 Postgres 的逻辑复制功能实现最小停机时间的迁移。要求源和目标都使用 Postgres 10 及以上版本。

🌐 This method allows migration with minimal downtime using Postgres's logical replication feature. Requires Postgres 10+ on both source and target.

什么时候使用逻辑复制 #

🌐 When to use logical replication

  • 你只需要很短的停机时间(几分钟而不是几小时)
  • 源数据库是 Postgres 10 或更高版本
  • 你可以在源端配置逻辑复制
  • 数据库写入活动很频繁,不能长时间暂停

源 Postgres 前提条件 #

🌐 Source Postgres prerequisites

访问权限 #

🌐 Access & privileges

  • 具有创建发布权限并能读取表的连接字符串
  • 建议使用超级用户或复制权限

逻辑复制所需设置 #

🌐 Required settings for logical replication

  • wal_level = logical
  • max_wal_senders ≥ 1
  • max_replication_slots ≥ 1
  • 足够的 max_connections(当前 + 1 用于订阅)

复制身份 #

🌐 Replica identity

每个接收 UPDATE/DELETE 的表必须有一个副本标识(通常是主键)。对于没有的表:

🌐 Every table receiving UPDATE/DELETE must have a replica identity (typically a PRIMARY KEY). For tables without one:

1
ALTER TABLE schema.table_name REPLICA IDENTITY FULL;

未复制的物品 #

🌐 Non-Replicated items

  • DDL 更改(模式修改)
  • 序列(需要手动同步)
  • 大对象 (LOBs)(使用 dump/restore 或存储在常规 bytea 列中)

计划一下模式冻结,切换前同步序列,并单独处理大对象。

🌐 Plan a schema freeze, sequence sync before cutover, and handle LOBs separately.

步骤 1:配置源数据库 #

🌐 Step 1: Configure source database

编辑 Postgres 配置文件:

🌐 Edit Postgres configuration files:

Postgres.conf#

1
# Set Supabase connection (Session Pooler on port 5432 or direct connection)
2
export SUPABASE_DB_URL="Postgres://postgres.[ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres"
3
4
# Set WAL level to logical
5
wal_level = logical
6
7
# Ensure sufficient replication slots
8
max_replication_slots = 10
9
10
# Ensure sufficient WAL senders
11
max_wal_senders = 10
12
13
# Set appropriate max_connections (current connections + 1 for subscription)
14
max_connections = 200 # Adjust based on your needs
15
16
# Optional: Enable SSL for secure replication
17
ssl = on
18
19
# Allow connections from Supabase
20
listen_addresses = '*' # Or specific IP addresses

pg_hba.conf#

1
# Allow replication connections from Supabase
2
# Replace <supabase_ip_range> with actual Supabase IP range
3
host replication all <supabase_ip_range> md5
4
host all all <supabase_ip_range> md5
5
6
# With SSL:
7
hostssl replication all <supabase_ip_range> md5
8
hostssl all all <supabase_ip_range> md5

重启 Postgres:

🌐 Restart Postgres:

1
sudo systemctl restart Postgres
2
sudo systemctl status Postgres

步骤 2:核实配置 #

🌐 Step 2: Verify configuration

1
-- Should return 'logical'
2
SHOW wal_level;
3
4
-- Check other parameters
5
SHOW max_replication_slots;
6
SHOW max_wal_senders;
7
8
-- Check current connections
9
SELECT count(*) FROM pg_stat_activity;

步骤 3:检查并设置副本标识 #

🌐 Step 3: Check and set replica identity

1
-- Find tables without primary keys
2
SELECT n.nspname, c.relname
3
FROM pg_class c
4
JOIN pg_namespace n ON n.oid = c.relnamespace
5
LEFT JOIN pg_constraint pk ON pk.conrelid = c.oid AND pk.contype = 'p'
6
WHERE c.relkind = 'r'
7
AND pk.oid IS NULL
8
AND n.nspname NOT IN ('pg_catalog','information_schema');
9
10
-- For tables without a primary key, set REPLICA IDENTITY FULL
11
ALTER TABLE my_schema.my_table REPLICA IDENTITY FULL;

步骤4:仅导出并恢复模式 #

🌐 Step 4: Export and restore schema only

1
# Export schema from source
2
pg_dump \
3
-h <source_host> \
4
-U <source_user> \
5
-p <source_port> \
6
-d <source_database> \
7
--schema-only \
8
--no-privileges \
9
--no-subscriptions \
10
--format=directory \
11
-f ./schema_dump
12
13
# Restore schema to Supabase (use Session Pooler)
14
pg_restore \
15
--dbname="$SUPABASE_DB_URL" \
16
--format=directory \
17
--schema-only \
18
--no-privileges \
19
--single-transaction \
20
--verbose \
21
./schema_dump

第5步:在源上创建发布物 #

🌐 Step 5: Create publication on source

1
-- Create publication for all tables
2
CREATE PUBLICATION supabase_migration FOR ALL TABLES;
3
4
-- Or for specific tables only (doesn't require superuser)
5
CREATE PUBLICATION supabase_migration FOR TABLE
6
schema1.table1,
7
schema1.table2,
8
public.table3;
9
10
-- Verify publication was created
11
SELECT * FROM pg_publication;

第6步:在Supabase上创建订阅 #

🌐 Step 6: Create subscription on Supabase

连接到你的 Supabase 数据库:

🌐 Connect to your Supabase database:

1
-- Create subscription with SSL (recommended)
2
CREATE SUBSCRIPTION supabase_subscription
3
CONNECTION 'host=<source_host> port=<source_port> user=<source_user> password=<source_password> dbname=<source_database> sslmode=require'
4
PUBLICATION supabase_migration;
5
6
-- Or without SSL (if source doesn't support it)
7
CREATE SUBSCRIPTION supabase_subscription
8
CONNECTION 'host=<source_host> port=<source_port> user=<source_user> password=<source_password> dbname=<source_database> sslmode=disable'
9
PUBLICATION supabase_migration;

步骤7:监控复制状态 #

🌐 Step 7: Monitor replication status

1
-- On Supabase (subscriber) - check subscription status
2
select * from pg_subscription_rel;
3
4
-- srsubstate = 'r' means ready (synchronized)
5
-- srsubstate = 'i' means initializing
6
-- srsubstate = 'd' means data is being copied
7
8
-- Overall subscription status
9
select * from pg_stat_subscription;
10
11
-- On source database - check replication status
12
select * from pg_stat_replication;
13
14
-- Check replication lag
15
select
16
slot_name,
17
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) as lag_size
18
from pg_replication_slots;

等所有桌子都显示 srsubstate = 'r'(准备好)状态。

🌐 Wait until all tables show srsubstate = 'r' (ready) status.

步骤 8:同步序列 #

🌐 Step 8: Synchronize sequences

在初始数据同步完成之后,但在切换到 Supabase 之前:

🌐 After initial data sync is complete, but BEFORE switching to Supabase:

1
# Set source to read-only
2
psql -h <source_host> -c "ALTER DATABASE <source_database> SET default_transaction_read_only = true;"
3
4
# Export sequences from source
5
pg_dump \
6
-h <source_host> \
7
-U <source_user> \
8
-p <source_port> \
9
-d <source_database> \
10
--data-only \
11
--table='*_seq' \
12
--table='*_id_seq' > sequences.sql
13
14
# Import sequences to Supabase
15
psql "$SUPABASE_DB_URL" -f sequences.sql

第9步:切换到Supabase #

🌐 Step 9: Switch to Supabase

  1. 确保复制延迟为零:
1
-- On Supabase
2
select * from pg_stat_subscription;
3
-- Check that latest_end_lsn is current
  1. 停止向源数据库写入(如果还不是只读的话)
  2. 在 Supabase 取消订阅:
1
DROP SUBSCRIPTION supabase_subscription;
  1. 更新应用的连接字符串以指向 Supabase
  2. 验证应用功能

第10步:清理 #

🌐 Step 10: Cleanup

在源数据库上(迁移成功后):

🌐 On source database (after successful migration):

1
-- Remove publication
2
DROP PUBLICATION supabase_migration;
3
4
-- Check and remove any remaining replication slots
5
SELECT * FROM pg_replication_slots;
6
DROP REPLICATION SLOT slot_name; -- if any remain
7
8
-- The source database should remain read-only or be decommissioned
9
-- Do NOT re-enable writes to avoid a split-brain scenario!

逻辑复制故障排除 #

🌐 Troubleshooting logical replication

问题解决方案
"无法连接到发布者"检查网络连接、防火墙规则、pg_hba.conf
"角色不存在"确保源端有复制用户,并且拥有 REPLICATION 权限
"发布不存在"核实发布名称,并确认发布已成功创建
复制延迟增加检查网络带宽、源数据库负载,增加 WAL 发送器
表卡在 i 状态检查源表是否有锁,确认表结构匹配
"复制槽已用尽"在 Postgres.conf 中增加 max_replication_slots

重要的限制 #

🌐 Important limitations

  • DDL 更改:模式修改不会被复制 - 迁移期间请冻结模式
  • 序列:切换前需要手动同步
  • 大对象 (LOBs):不进行复制 - 使用转储/恢复或存储在常规 bytea 列中
  • 自定义类型:可能需要特别处理
  • 用户和角色:必须在 Supabase 上手动重新创建

有关详细限制,请参见 Postgres 逻辑复制限制

🌐 For detailed restrictions, see Postgres Logical Replication Restrictions

什么时候使用哪种方法 #

🌐 When to use which method

使用 Dump/Restore 的情况:

  • 停机时间可以接受
  • 源是 Postgres 版本低于 10
  • 更简单的流程更好
  • 无法在源端配置逻辑复制

在以下情况下使用逻辑复制:

  • 所需停机时间最少
  • 两边都是 Postgres 10 以上
  • 可以修改源配置
  • 拥有复制权限

获取帮助 #

🌐 Getting help