Skip to content
Local Development

本地开发工作流程

Set up and run your day-to-day local development workflow with the Supabase CLI.

本指南介绍了使用 Supabase CLI 本地开发的两种常见起点,并展示了它们如何汇合到相同的日常工作流程中。到最后,你的仓库中将会有一个 ./supabase 目录,任何人都可以克隆它来在本地或全新的远程实例上重现完整项目。

🌐 This guide walks through two common starting points for local development with the Supabase CLI, and shows how they converge into the same daily workflow. By the end, you'll have a ./supabase directory in your repo that anyone can clone to recreate the full project, locally or on a fresh remote instance.

有两个起点,但都通向同一个地方:数据库模式和在版本控制中跟踪的迁移,以及用于本地开发的种子数据。

🌐 There are two starting points, both leading to the same place: database schema and migrations tracked in version control, with seed data for local development.

在你开始之前 #

🌐 Before you begin

你需要安装 Supabase CLI,并运行一个支持 Docker 的运行环境。如果你还没设置好,可以查看 安装和运行 CLI 来获取 macOS、Windows 和 Linux 的安装指南,以及 supabase start 启动了什么服务和如何访问每个服务的详细信息。

🌐 You need the Supabase CLI installed and a Docker-compatible runtime running. If you haven't set these up yet, see Install and run the CLI for installation across macOS, Windows, and Linux, and for the details of what supabase start brings up and how to access each service.

本指南假设你只运行一个本地项目。如果你同时处理多个应用或 git 工作树,并且每个都需要一个本地项目,请参见 运行多个本地项目。

🌐 This guide assumes one running local project. If you work on several apps or git worktrees at once and need a local project for each, see Running multiple local projects.

请记住,本地环境仅用于开发。它没有经过生产环境的加固,绝不能暴露给外部流量。它没有 TLS、没有速率限制,并使用默认凭据。可以用它来开发和测试,然后将其部署到 Supabase 平台 或合适的自托管环境,用于其他所有用途。

🌐 Keep in mind that the local stack is for development only. It is not hardened for production use and must never be exposed to external traffic. It has no TLS, no rate limiting, and default credentials. Use it to develop and test, then deploy to the Supabase Platform or a proper self-hosted setup for anything beyond that.

./supabase#

🌐 The ./supabase directory [#the-supabase-directory]

在 supabase init 之后,你的项目会包含一个 ./supabase 目录。这里是它的内容以及需要提交的内容:

🌐 After supabase init, your project contains a ./supabase directory. Here's what goes in it and what to commit:

路径目的提交?
config.toml本地堆栈配置(端口、认证设置等)是
migrations/按顺序执行的带时间戳 SQL 迁移文件是
seed.sql开发/测试数据,在 start 和 db reset 的迁移之后应用是
schemas/声明式模式文件(如果使用该方法)是
.temp/、.branches/CLI 内部状态否

config.toml 是可以安全提交的。默认情况下它不包含任何密钥信息。如果你添加了敏感信息(OAuth 凭证、API 密钥),请使用 env() 功能来引用环境变量,而不是硬编码它们。查看 管理配置和密钥。

🌐 The config.toml is safe to commit. It contains no secrets by default. If you add sensitive values (OAuth credentials, API keys), use the env() function to reference environment variables instead of hardcoding them. See Managing config and secrets.

你用的是哪个 diff 引擎 #

🌐 Which diff engine you're on [#pg-delta]

db diff、db pull 和 db schema declarative 命令使用差异引擎生成 SQL。CLI 自带两个引擎。pg-delta 是用于最近 supabase init 创建的项目的引擎,而 migra 是旧版引擎。

你的项目使用哪种差异引擎取决于 config.toml。如果它包含一个带有 enabled = true 的 [experimental.pgdelta] 部分,你的项目将使用 pg-delta。如果该部分缺失或 enabled 是 false,你的项目则会使用传统的 migra 引擎。查看 差异引擎 了解两者的区别以及如何切换。

🌐 Which diff engine your project uses depends on config.toml. If it contains an [experimental.pgdelta] section with enabled = true, your project uses pg-delta. If the section is missing or enabled is false, your project uses the legacy migra engine. See Diff engines for how the two differ and how to switch.

本指南描述了 pg-delta 的行为,并指出了 migra 不同的地方。db schema declarative 命令需要 pg-delta,在 migra 上无法运行。有关并排比较和切换操作步骤,请参见 Diff engines。

🌐 This guide describes pg-delta behavior and calls out where migra behaves differently. The db schema declarative commands require pg-delta and won't run on migra. For a side-by-side comparison and a switching procedure, see Diff engines.

把现有项目移到本地开发 #

🌐 Move an existing project to local development

你已经在 Supabase 平台上搭建了一个项目,通过仪表板、SQL 编辑器或客户端库创建了表。现在你想要一个本地开发环境,并将所有内容纳入版本控制。

🌐 You've built a project on the Supabase platform, with tables created via the Dashboard, SQL editor, or client libraries. Now you want a local dev setup with everything in version control.

步骤 1:初始化 #

🌐 Step 1: Initialize

在你的项目根目录下:

🌐 In your project root:

supabase init

这会创建 ./supabase/config.toml。如果你已经有一个包含应用代码的项目目录,请在根目录运行这个命令。supabase/ 目录会和你的应用代码并列放置。

🌐 This creates ./supabase/config.toml. If you already have a project directory with application code, run this at the root. The supabase/ directory will sit alongside your app code.

步骤 2:认证 #

🌐 Step 2: Authenticate

supabase login

打开浏览器以生成访问令牌。该令牌会保存在本地,并用于所有后续与平台交互的 CLI 命令。

🌐 Opens a browser to generate an access token. The token is stored locally and used for all subsequent CLI commands that interact with the platform.

🌐 Step 3: Link to your remote project

supabase link --project-ref <project-id>

在 Supabase 仪表板的 URL 中找到你的项目 ID:https://supabase.nodejs.cn/dashboard/project/<project-id>。

🌐 Find your project ID in the Supabase Dashboard URL: https://supabase.nodejs.cn/dashboard/project/<project-id>.

这告诉命令行工具要连接哪个远程项目,以进行 db pull、db push 以及其他远程操作。系统会提示你输入数据库密码,也就是你创建项目时设置的密码。

🌐 This tells the CLI which remote project to connect to for db pull, db push, and other remote operations. You'll be prompted for the database password, which is the password set when you created the project.

第4步:拉取远程模式 #

🌐 Step 4: Pull the remote schema

supabase db pull

这会从你本地的 supabase/migrations 目录(此时是空的)构建一个影子数据库,对比你的远程数据库,并将差异保存为迁移文件:

🌐 This builds a shadow database from your local supabase/migrations directory (empty at this point), diffs your remote database against it, and saves the difference as a migration file:

supabase/migrations/<timestamp>_remote_schema.sql

在这次初始拉取中,整个迁移都来自那个 diff,它把你的远程 schema 捕获为可执行的 SQL。这次迁移就是你的基线。之后的所有更改都会建立在它的基础上。db pull 还提供了将这次迁移记录为已在远程迁移历史(supabase_migrations.schema_migrations 表)中应用的选项。接受它(非交互式运行会自动接受),这样以后 db push 就不会尝试重新应用它了。

🌐 On this initial pull, the whole migration comes from that diff, which captures your remote schema as executable SQL. This migration is your baseline. All future changes build on top of it. db pull also offers to record this migration as already applied in the remote migration history (the supabase_migrations.schema_migrations table). Accept it (non-interactive runs accept automatically) so a later db push won't try to reapply it.

如果一次更改跨越了事务边界,db pull 可能会写入多个有序迁移文件,而不是单个文件。把它们全部提交。在老旧的 migra 引擎上,这次初始拉取会用 pg_dump 填充迁移,并附上转储跳过部分的差异。

🌐 If a change crosses a transaction boundary, db pull may write more than one ordered migration file instead of a single file. Commit all of them. On the legacy migra engine, this initial pull seeds the migration with pg_dump and appends a diff of what the dump skips.

在使用 --db-url 连接 db pull 或 db diff 时,优先选择直接连接(db.<project-ref>.supabase.co:5432),这样 pg-delta 才能读取完整目录。直接连接需要 IPv6 或 IPv4 附加功能,所以在只有 IPv4 的网络上,请改用会话池。不要对这些命令使用事务池。对于 db dump 和 psql,会话池是安全的默认选择。

步骤5:创建种子数据 #

🌐 Step 5: Create seed data

你有两个选择:

🌐 You have two options:

选项A:从远程导出现有数据(然后清理一下):

supabase db dump --data-only --linked > supabase/seed.sql

选项B:手动编写种子数据(大多数项目推荐):

使用 INSERT 语句创建 supabase/seed.sql,设置一个有用的本地开发状态,比如几个测试用户和示例数据。这通常比直接导出生产数据更好,因为你可以完全控制里面的内容。

🌐 Create supabase/seed.sql with INSERT statements that set up a useful local development state, such as a few test users and sample data. This is often better than dumping production data because you control exactly what's in it.

想了解更多关于组织种子文件、glob 模式以及生成真实数据的信息,请参见 给你的数据库添加种子。

🌐 For more on organizing seed files, glob patterns, and generating realistic data, see Seeding your database.

第6步:核实 #

🌐 Step 6: Verify

supabase start
supabase db reset

db reset 会销毁本地数据库并从头重新创建:它会按顺序应用所有迁移,然后运行 seed.sql。如果成功,你的环境就是可复现的。任何克隆该仓库的人都可以这样做。

第7步:提交 #

🌐 Step 7: Commit

git add supabase/
git commit -m "add supabase local development setup"

你的项目现在有了一个完全可复现的本地开发环境。

🌐 Your project now has a fully reproducible local development environment.

从零开始一个新项目 #

🌐 Start a new project from scratch

还没有远程项目。你是从零开始构建,想从一开始就做好。

🌐 No remote project yet. You're building from scratch and want to do it right from the start.

步骤 1:初始化 #

🌐 Step 1: Initialize

supabase init

第2步:启动本地堆栈 #

🌐 Step 2: Start the local stack

supabase start

首次运行时,会拉取 Docker 镜像,这需要几分钟。之后启动就很快了。运行后,CLI 会输出本地服务的 URL 和凭证,包括本地 Dashboard 实例的 Studio URL。有关完整输出和如何访问每个服务,请参见 安装和运行 CLI。

🌐 On first run, Docker images are pulled, which takes a few minutes. Subsequent starts are fast. Once running, the CLI outputs local service URLs and credentials, including the Studio URL for a local instance of the Dashboard. See Install and run the CLI for the full output and how to reach each service.

步骤 3:创建你的模式 #

🌐 Step 3: Create your schema

两种方法,选一个:

🌐 Two approaches, pick one:

选项 A:声明式模式(推荐用于新项目)

将你希望数据库达到的状态声明为 supabase/schemas/ 中的一个文件,例如:

🌐 Declare the state you want your database to be in as a file in supabase/schemas/, for example:

create table public.todos (
id bigint generated by default as identity primary key,
created_at timestamptz default now() not null,
title text not null,
is_complete boolean default false not null,
user_id uuid references auth.users (id) default auth.uid() not null
);
alter table public.todos enable row level security;
create policy "Users can read their own todos"
on public.todos for select
using (auth.uid() = user_id);
create policy "Users can create their own todos"
on public.todos for insert
with check (auth.uid() = user_id);

然后从它生成一个迁移:

🌐 Then generate a migration from it:

supabase db schema declarative sync -f initial-schema

这会将你声明的 schema 文件与你(当前为空的)迁移历史进行比较,并将差异写入 supabase/migrations/ 作为迁移文件。然后命令会提示你是否将迁移应用到本地数据库。在脚本中传入 --apply 或 --no-apply 可跳过提示。全局 --yes 标志同样适用。如果没有使用这些标志,在非交互式运行(CI 或没有终端的代理)下,会写入文件并默默跳过应用步骤。

🌐 This compares your declared schema files against your (currently empty) migration history and writes the difference as a migration file in supabase/migrations/. The command then offers to apply the migration to your local database. Pass --apply or --no-apply to skip the prompt in scripts. The global --yes flag also applies it. Without one of those flags, a non-interactive run (CI, or an agent without a terminal) writes the file and silently skips the apply step.

db schema declarative 命令需要 pg-delta,而 supabase init 已经为你启用了它(在 config.toml 的 [experimental.pgdelta] enabled = true 中)。要了解完整的声明式工作流,包括管理视图和函数以及已知注意事项,请参见 声明式数据库架构。

🌐 The db schema declarative commands require pg-delta, which supabase init enabled for you ([experimental.pgdelta] enabled = true in config.toml). For the full declarative workflow, including managing views and functions and known caveats, see Declarative database schemas.

选项 B:直接编写迁移

supabase migration new initial-schema

这会在 supabase/migrations/<timestamp>_initial-schema.sql 创建一个空文件。在里面写你的 SQL,然后执行:

supabase db reset

步骤4:添加种子数据 #

🌐 Step 4: Add seed data

创建 supabase/seed.sql:

🌐 Create supabase/seed.sql:

-- Create a test user (Supabase Auth)
-- Note: this is a placeholder row so seeded data has a user_id to reference.
-- It has no password, so it can't be used to sign in. To create a
-- login-capable user, use the Auth admin API or the local Studio.
insert into auth.users (id, email, raw_user_meta_data)
values ('d0e3c8f0-1234-5678-9abc-def012345678', 'test@example.com', '{}');
-- Seed application data
insert into public.todos (title, user_id)
values
('Buy groceries', 'd0e3c8f0-1234-5678-9abc-def012345678'),
('Write documentation', 'd0e3c8f0-1234-5678-9abc-def012345678');

步骤5:核实 #

🌐 Step 5: Verify

supabase db reset

清空一切,应用迁移,运行种子。如果通过了,你的项目就是可复现的。

🌐 Drops everything, applies migrations, runs seed. If this passes, your project is reproducible.

第6步:提交 #

🌐 Step 6: Commit

git add supabase/
git commit -m "add supabase local development setup"

日常工作流程 #

🌐 The daily workflow

两个起点在这里汇合。你的仓库里已经有一个可用的 ./supabase 目录。日常开发就是这样进行的。

🌐 Both starting points converge here. You have a working ./supabase directory in your repo. Here's how day-to-day development works.

进行模式更改 #

🌐 Making schema changes

你使用哪种方法是项目层面的决定,在你第一次创建模式时就已经确定了——不是每次更改时的选择。这取决于你是否在 supabase/schemas/ 中保留声明性文件。选择与你的项目匹配的标签。

🌐 Which approach you use is a project-level decision, set when you first created your schema - not a per-change choice. It depends on whether you keep declarative files in supabase/schemas/. Pick the tab that matches your project.

这些步骤假设使用 pg-delta 引擎。在传统的 migra 引擎上,需要使用 supabase db diff 而不是 db schema declarative sync 来生成迁移,并参考传统 migra 引擎上的声明式模式。

🌐 These steps assume the pg-delta engine. On the legacy migra engine, generate the migration with supabase db diff instead of db schema declarative sync, and follow Declarative schemas on the legacy migra engine.

  1. 在 supabase/schemas/ 中编辑你的 schema 文件(添加表、列、策略等)
  2. 生成一个迁移:supabase db schema declarative sync -f add-due-date-to-todo
  3. 查看生成的迁移文件。请参阅 清理生成的迁移
  4. 验证完整链条:supabase db reset
  5. 把模式文件和迁移一起提交

生成类型 #

🌐 Generating types

如果你的应用使用了生成的 TypeScript 类型,每当你的模式发生变化时都要重新生成它们:

🌐 If your app uses the generated TypeScript types, regenerate them whenever your schema changes:

supabase gen types --lang typescript --local > database.types.ts

使用 --linked 而不是 --local 从你的远程项目生成。TypeScript 是默认语言;如果是其他语言,可以传入 --lang go、--lang swift 或 --lang python。

🌐 Use --linked instead of --local to generate from your remote project. TypeScript is the default language; pass --lang go, --lang swift, or --lang python for others.

关于使用生成的类型(辅助类型、JSON 推断、类型安全查询)以及在 CI 中自动重新生成,请参阅 生成类型。

🌐 For working with the generated types (helper types, JSON inference, type-safe queries) and automating regeneration in CI, see Generating types.

与团队保持同步 #

🌐 Staying in sync with your team

当别人推送新的迁移时:

🌐 When someone else pushes new migrations:

git pull
supabase db reset

db reset 会从头重放所有迁移,因此你总是会与仓库的当前状态保持一致。

推送到远程项目 #

🌐 Pushing to a remote project

当你准备好将你的模式部署到远程 Supabase 实例时:

🌐 When you're ready to deploy your schema to a remote Supabase instance:

# Authenticate (if not already)
supabase login
# Link to the remote project (if not already)
supabase link --project-ref <project-id>
# Preview what will be applied
supabase db push --dry-run
# Apply migrations
supabase db push

db push 只会应用那些还没在远程应用的迁移。它通过远程数据库上自动创建的 supabase_migrations.schema_migrations 表来跟踪这些迁移。

要同时初始化一个新的远程实例(仅限开发/预发布环境):

🌐 To also seed a fresh remote instance (dev/staging environments only):

supabase db push --include-seed

重置远程开发或预发布项目 #

🌐 Resetting a remote dev or staging project

如果开发或预发布环境的远程库出现偏差或变得混乱,你可以清空它,然后从本地迁移重新构建:

🌐 If a dev or staging remote drifts or gets into a messy state, you can wipe it and rebuild it from your local migrations:

supabase db reset --linked

与默认的 supabase db reset 不同,supabase db reset 针对的是你的本地数据库,而 --linked 标志则针对你通过 supabase link 连接的远程项目:它会删除远程模式,按顺序重放每个本地迁移,然后运行你的种子文件。传入 --no-seed 可以跳过种子操作。

🌐 Unlike the default supabase db reset, which targets your local database, the --linked flag runs against the remote project you connected with supabase link: it drops the remote schema, replays every local migration in order, then runs your seed files. Pass --no-seed to skip seeding.

对于带有 CI/CD 的多环境设置(功能分支、预发布、生产环境),请参阅 管理环境。

🌐 For multi-environment setups with CI/CD (feature branches, staging, production), see Managing Environments.

快捷键一览 #

🌐 Key commands at a glance

命令它的功能
supabase init创建 ./supabase/config.toml
supabase start启动本地栈,应用迁移 + 种子数据
supabase stop停止本地堆栈(数据会一直保留到 db reset)
supabase db reset销毁本地数据库,重新执行所有迁移并从头导入初始数据
supabase db reset --linked销毁 远程关联 数据库,并从本地迁移 + 种子重建它(破坏性操作,仅用于开发/测试环境)
supabase db diff -f <name>通过将实时数据库(默认本地)与由迁移构建的影子数据库进行对比来生成迁移
supabase db schema declarative sync将 supabase/schemas/ 与你的迁移进行对比,并将差异写入新的迁移文件
supabase db schema declarative generate将实时数据库导出到 supabase/schemas/ 下的声明性架构文件
supabase db pull将远程架构拉取到新的本地迁移文件中
supabase db pull --declarative从远程数据库更新 supabase/schemas/ 而不是创建迁移。仅 pg-delta 项目
supabase db push将待处理的本地迁移应用到远程数据库
supabase db dump通过 pg_dump 导出远程数据库架构(或者用 --data-only 导出数据)
supabase migration new <name>创建一个空的迁移文件
supabase migration list将本地迁移与远程迁移历史进行比较
supabase gen types --lang typescript从你的数据库模式生成 TypeScript 类型
supabase link --project-ref将本地项目连接到远程 Supabase 项目
supabase login使用 Supabase 平台进行身份验证

要查看完整的命令参考和所有标志,请参阅 CLI 参考。

🌐 For the full command reference and every flag, see the CLI reference.

清理生成的迁移文件 #

🌐 Cleaning up generated migrations

当 supabase db diff 或 db schema declarative sync 生成迁移时,提交前先审查一下。

🌐 When supabase db diff or db schema declarative sync generates a migration, review it before committing.

pg-delta#

🌐 What pg-delta output looks like

生成的 SQL 使用大写关键字,最大换行宽度为 180 个字符。你可以在 config.toml 中用 [experimental.pgdelta] format_options 覆盖这个设置,或者设置 format_options = "null" 来输出不做任何格式化的原始语句。

🌐 Generated SQL uses uppercase keywords, wrapped at a maximum width of 180 characters. You can override this with [experimental.pgdelta] format_options in config.toml, or set format_options = "null" to emit raw statements with no formatting applied.

大多数更改会生成一个迁移文件。当一个更改跨越了事务边界(例如 alter type ... add value 后跟一个使用新枚举值的检查约束,而它们不能在同一事务中运行)时,CLI 可能会为每个单元分别写一个有顺序的迁移文件。额外的文件会带有一个数字段后缀,比如 <timestamp>_add-status_1.sql 和 <timestamp+1s>_add-status_2.sql。把它们都提交了。

🌐 Most changes produce a single migration file. When a change crosses a transaction boundary (for example alter type ... add value followed by a check constraint that uses the new enum value, which can't run in the same transaction), the CLI may write one ordered migration file per unit instead. The extra files carry a numeric segment suffix, such as <timestamp>_add-status_1.sql and <timestamp+1s>_add-status_2.sql. Commit all of them.

一个不能在事务中运行的迁移,它的第一行以这个指令开头:

🌐 A migration whose statements can't run inside a transaction starts with this directive on its first line:

-- pg-delta: transaction=false

db reset、db push 和 migration up 通过在没有封装事务的情况下运行文件里的语句来遵循它。保留这行。CLI 能自己检测到 create index concurrently 并且即使没有这个指令也能单独运行,但其他不能在事务中运行的语句则依赖它。这个指令还会改变失败时的处理方式。如果没有封装事务,某个语句失败了,文件中先前的语句仍然会生效。

通过 GitHub 集成 部署不会遵守这个指令,而是把每个迁移都放在事务里执行,所以这些迁移在那儿会失败。并不是每个拆分文件都有这个指令。alter type ... add value 自己在事务中运行,所以它的文件是独立的,但没有这个指令。

🌐 Deploys through the GitHub integration don't honor the directive and run every migration inside a transaction, so these migrations fail there. Not every split file carries it. alter type ... add value runs in its own transaction, so its file is separate but has no directive.

扩展声明 #

🌐 Extension statements

CREATE EXTENSION IF NOT EXISTS ... 或 DROP EXTENSION ... 可能会在你的本地和远程扩展集不同的时候出现。如果该声明反映了你想要的更改,就保留它。如果该扩展已经在之前的迁移中处理过,或者你不想更改它,就删除它。要慎重决定,因为 DROP EXTENSION 会在 db reset 上默默生效。

扩展自己创建和管理的对象,比如 pg_partman 维护的分区和 pgmq 创建的队列表,会被识别为扩展管理的对象。差异不会对它们发出原始的 create table 或 drop table 语句。相反,它通过扩展自身的 API 表达更改,比如 select pgmq.drop_queue('q'); 或 delete from partman.part_config 行,并且 CLI 会把这些语句标记为破坏性操作。像审查其他删除操作一样,仔细查看这些操作。

🌐 Objects that extensions create and manage themselves, such as partitions maintained by pg_partman and queue tables created by pgmq, are recognized as extension-managed. The diff never emits raw create table or drop table statements for them. Instead it expresses changes through the extension's own API, such as select pgmq.drop_queue('q'); or a delete from partman.part_config row, and the CLI flags those statements as destructive. Review them as carefully as any other drop.

覆盖警告 #

🌐 Coverage warnings

pg-delta 会把它不跟踪的架构对象(比如类型转换、操作符和文本搜索配置)报告为警告,而不是默默地忽略它们。可以通过手动编写迁移来添加这些对象。要把这些警告变成严格的错误(在 CI 中很有用),传入 --strict-coverage。

授予和撤销模式 #

🌐 Grants and revoke patterns

两个引擎都把权限当作 schema 状态的一部分,所以生成的迁移可能会包含你没写过的授予语句。新表可能带有针对默认角色的显式 GRANT 行,而第一次对现有数据库做差异比较时,可能会生成一长串 REVOKE ALL,后面跟着从默认权限得出的 GRANT 语句。这些语句也可能源于两个数据库之间默认权限的差异,所以在删除它们之前,先检查一下这些角色在目标数据库上是否已经拥有了预选项限。如果有,而且你没有改动权限,这些行删掉是安全的。团队里要保持一致,看大家是保留还是删除这些语句。

🌐 Both engines treat permissions as part of the schema state, so generated migrations can include grant statements you didn't write. New tables can come with explicit GRANT lines for the default roles, and a first diff against an existing database can emit long runs of REVOKE ALL followed by GRANT statements derived from default privileges. These statements can also come from default-privilege differences between the two databases, so before removing them, check that the roles already hold the intended privileges on the target database. If they do and you haven't changed permissions, the lines are safe to remove. Be consistent across your team about whether you keep or remove them.

db diff#

🌐 Known limitations of db diff

没有哪个差异引擎能捕捉到所有内容。DML(INSERT、UPDATE、DELETE)从来不会被跟踪,所以你必须手动将数据更改添加到迁移中。这包括存储桶,它们是 storage.buckets 表中的行,而不是模式对象。详见声明式模式指南中的完整注意事项列表。

🌐 No diff engine captures everything. DML (INSERT, UPDATE, DELETE) is never tracked, so you must add data changes to the migration by hand. This includes storage buckets, which are rows in the storage.buckets table rather than schema objects. See the full list of caveats in the declarative schemas guide.

如果一个差异看起来不对,你可以在单次运行中回退到旧版引擎(db diff --use-migra 或 db pull --diff-engine migra)进行比较,或者在 [experimental.pgdelta] 下完全选择退出 enabled = false。查看 Diff engines 了解引擎选择的工作方式以及两者之间的差异。

🌐 If a diff looks wrong, you can fall back to the legacy engine for a single run (db diff --use-migra, or db pull --diff-engine migra) to compare, or opt out entirely with enabled = false under [experimental.pgdelta]. See Diff engines for how engine selection works and what differs between the two.

把生成的输出当作草稿,而不是最终迁移。如果有疑问,查看生成的 SQL 并手动调整。

🌐 Treat generated output as a draft, not a final migration. When in doubt, review the generated SQL and adjust it manually.

故障排除 #

🌐 Troubleshooting

db reset 因迁移错误而失败

输出会显示哪个迁移文件失败以及 SQL 错误。修复迁移文件后,再次运行 db reset。

🌐 The output will show which migration file failed and the SQL error. Fix the migration file, then run db reset again.

db push 表示迁移已经应用

远程数据库的历史里已经有那些迁移了。运行 supabase migration list 来比较本地和远程状态。如果它们不同步,使用 supabase migration repair 来纠正远程历史。

🌐 The remote database already has those migrations in its history. Run supabase migration list to compare local vs. remote state. If they're out of sync, use supabase migration repair to correct the remote history.

模式漂移:远程在迁移之外被更改

如果有人直接修改了远程数据库(通过仪表盘、SQL 编辑器等),运行 supabase db pull 将这些更改捕获为新的迁移文件。然后在本地运行 supabase db reset 来验证一切是否仍然正常。

🌐 If someone modified the remote database directly (via Dashboard, SQL editor, etc.), run supabase db pull to capture those changes as a new migration file. Then supabase db reset locally to verify everything still works.

db pull 打印 “未找到架构更改” 并以非零状态退出

本地和远程已经同步,所以没有东西可拉。如果你在 CI 中使用脚本 db pull,会得到非零退出码。空的 db diff 会返回 0。

🌐 Local and remote are already in sync, so there is nothing to pull. If you script db pull in CI, expect a non-zero exit code. An empty db diff exits 0 instead.

db diff 警告 schema_paths 被忽略

在 pg-delta 下,声明性文件从不属于 db diff 基线,因此 [db.migrations].schema_paths 对它没有影响。请改用 supabase db schema declarative sync 从声明性文件生成迁移。

🌐 Under pg-delta, declarative files are never part of the db diff baseline, so [db.migrations].schema_paths has no effect on it. Generate migrations from declarative files with supabase db schema declarative sync instead.

启用 pg-delta 后的第一次拉动出乎意料的大

当你的迁移历史是从旧的 migra 差异构建的时,就会发生这种情况,而这些差异没有跟踪诸如评论、域、角色和发布成员之类的对象。第一次在 pg-delta 上的 db pull 会在一次性补充迁移中捕获这些对象。你的数据库已经有这些对象了,所以接受提示,将迁移记录为已应用,并像对待其他生成的迁移文件一样查看它。如果你的基线是从旧引擎的 pg_dump 路径来的,它已经包含了这些对象,并且第一次拉取会显示“未发现模式更改”。完整操作请参见 将现有项目切换到 pg-delta。

🌐 This happens when your migration history was built from legacy migra diffs, which didn't track objects such as comments, domains, roles, and publication membership. The first db pull on pg-delta captures those objects in a one-time catch-up migration. Your database already has them, so accept the prompt to record the migration as applied and review the file like any other generated migration. If your baseline came from the legacy engine's pg_dump path instead, it already contains those objects, and the first pull reports "No schema changes found". See Switch an existing project to pg-delta for the full procedure.

差异看起来不对或意外地返回为空

设置 PGDELTA_DEBUG=1 然后重新运行命令。CLI 会写一个调试包,里面包含提取的快照、计划和诊断信息。计划包会放在 supabase/.temp/pgdelta/v2/debug/<id>/ 下,失败运行的包会放在 supabase/.temp/pgdelta/debug/<id>/ 下。这个包显示了引擎看到的内容。提交 CLI 错误报告时请附上它。

supabase start上的Docker问题

确保 Docker 正在运行,并分配了至少 7 GB 的内存。如果容器健康检查失败,尝试:

🌐 Ensure Docker is running and has at least 7 GB of RAM allocated. If containers fail health checks, try:

supabase stop
supabase start

如果问题持续,使用 supabase stop --no-backup 进行彻底重启(这会删除本地数据库数据)。

🌐 If problems persist, supabase stop --no-backup for a clean restart (this removes local database data).

supabase start 失败,因为端口已被占用

另一个本地 Supabase 项目正在使用默认端口。请在其目录中使用 supabase stop 停止它。要同时运行两个项目,请启用实验性的 supabase stack 命令,并从每个项目的 config.toml 中移除固定端口。详情请参见 运行多个本地项目。

🌐 Another local Supabase project is using the default ports. Stop it with supabase stop from its directory. To run both projects at the same time, turn on the experimental supabase stack commands and remove the fixed ports from each project's config.toml. See Running multiple local projects.