Skip to content
Local Development

差异引擎:pg-delta 和 migra

How the Supabase CLI generates migrations, which engine your project uses, and how to switch.

一个 diff 引擎会比较两个数据库状态,并生成将一个状态转换为另一个状态的 SQL。它为 supabase db diff、supabase db pull 和 supabase db schema declarative 命令提供动力。CLI 自带两个引擎,同一个命令在不同引擎下可能有不同的表现。本页讲解了如何判断你使用的是哪个引擎,它们之间有什么不同,以及如何将现有项目从一个引擎切换到另一个。

🌐 A diff engine compares two database states and generates the SQL that turns one into the other. It powers supabase db diff, supabase db pull, and the supabase db schema declarative commands. The CLI ships two engines, and the same command can behave differently depending on which one your project uses. This page explains how to tell which engine you're on, what differs between them, and how to move an existing project from one to the other.

pg-delta 是 Supabase 的开源引擎,也是使用最近 supabase init 创建的项目的默认引擎。它不是通过解析 SQL 来理解你的模式,而是将每个状态加载到一个真实的 Postgres 实例中,并从目录中读取结果。它建模了遗留引擎遗漏的实体,比如注释、域、角色、发布成员以及视图上的安全调用者设置,同时支持 Postgres 14 到 18。它在 [experimental.pgdelta] 配置命名空间下发布,目前仍处于 1.0 之前的版本。

migra 是 djrobstep 的开源 Python 库,用于对比 Postgres 架构,并且自从 pg-delta 出现之前,CLI 就已经调用它了。它可以比较两个实时的 Postgres 数据库,并生成将一个变成另一个的 SQL,这就是 supabase db diff 背后的机制。没有选择加入 pg-delta 的项目仍然在使用它,而且他们依赖的每个命令都继续正常工作。

你们的项目用的是哪个引擎 #

🌐 Which engine your project uses

你的项目使用哪种差异引擎取决于 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.

使用最新 supabase init 创建的项目使用 pg-delta,因为 init 会把这个写入 config.toml:

🌐 Projects created with a recent supabase init use pg-delta because init writes this into config.toml:

supabase/config.toml
[experimental.pgdelta]
enabled = true

没有该部分的现有项目会继续使用旧的 migra 引擎,直到它们添加该部分。请参见 将现有项目切换到 pg-delta。

🌐 Existing projects without that section keep the legacy migra engine until they add it. See Switch an existing project to pg-delta.

如果想在不改变 config.toml 的情况下单次使用 migra,这个标志取决于命令:

🌐 To use migra for a single run without changing config.toml, the flag depends on the command:

命令回退到 migra 的标志
db diff--use-migra
db pull--diff-engine migra

要完全退出,请在 [experimental.pgdelta] 下设置 enabled = false。

🌐 To opt out entirely, set enabled = false under [experimental.pgdelta].

这些引擎有什么不同 #

🌐 What differs between the engines

这两个引擎的命令和迁移工作流程是一样的。不同的是每个命令读取什么、捕获什么以及写入什么。

🌐 The commands and the migration workflow are the same on both engines. What differs is what each command reads, what it captures, and what it writes.

行为pg-delta传统 migra
db diff 比较的内容总是将实时数据库与根据你的迁移构建的影子数据库进行比较。从不读取 supabase/schemas/。实时数据库与你的迁移进行比较,除非 supabase/schemas/ 包含声明式文件。那样的话,它会改为将这些文件与你的迁移进行比较。
从声明式文件生成迁移supabase db schema declarative syncsupabase db diff,本地堆栈已停止
将数据库导出为声明性文件supabase db schema declarative generate不可用。使用 supabase db dump 并手动拆分输出。
声明文件的排序自动,根据语句之间的依赖。[db.migrations].schema_paths 会被忽略,当设置中列出任何路径时,CLI 会发出警告。默认按字典顺序。[db.migrations].schema_paths 可覆盖顺序。即使设置为空,supabase/schemas/ 中的文件也会被使用。
初始 db pull(空迁移历史)将远程数据库与空的影子数据库进行对比。你在托管模式中的自定义内容,如 auth.users 上的触发器和 storage.objects 上的 RLS 策略,也会被包括在内。用 pg_dump 初始化迁移,这会跳过托管模式,然后在 auth 和 storage 中附加你触发器和 RLS 策略的差异。旧版本会排除那些模式,并提示你运行 supabase db pull --schema auth,storage。
后续 db pull 运行将远程数据库与你的迁移进行差异比较。相同。托管模式中的触发器和 RLS 策略更改也包括在内。
db pull --declarative在不创建迁移的情况下,替换所选数据库中的 supabase/schemas/。可以运行,但别用。它写入的树只有 db schema declarative 命令能读。老引擎上的 db diff 会尝试把那棵树当作基础线加载,然后失败。
引擎不跟踪的对象以警告的形式报告,绝不会静默丢弃。传入 --strict-coverage 可以将警告变为失败。静默忽略。--strict-coverage 没有任何效果。
生成的 SQL大写关键字在 180 个字符处换行。可通过 [experimental.pgdelta] format_options 配置。引擎默认格式。
每次运行的迁移文件通常是一个。当一个更改跨越事务边界时,它可能为每个单元写一个带有 _1、_2 后缀的有序文件。无法在事务中运行语句的文件以 -- pg-delta: transaction=false 开头。一个文件。
已知限制请参阅 已知注意事项。请参阅 旧引擎的限制。

要了解 pg-delta 的日常命令操作,请参阅 本地开发工作流程。要了解每个引擎的声明式工作流程,请参阅 声明式数据库架构。

🌐 For a walkthrough of the day-to-day commands on pg-delta, see Local development workflow. For the declarative workflow on each engine, see Declarative database schemas.

将现有项目切换到 pg-delta#

🌐 Switch an existing project to pg-delta [#switch-an-existing-project-to-pg-delta]

切换是一次性更改到 config.toml,然后进行补迁移。最好在一个分支上操作,这样你可以在它到达你的团队之前先审查所有内容。

🌐 Switching is a one-time change to config.toml followed by a catch-up migration. Do it on a branch so you can review everything before it reaches your team.

  1. 把引擎设置改成 config.toml:

    supabase/config.toml
    [experimental.pgdelta]
    enabled = true
  2. 如果你的项目使用声明式 schema,移除 [db.migrations].schema_paths。pg-delta 上会自动排序,CLI 会在设置列出任何路径时发出警告。

  3. 对你的关联项目拉取一次以创建一个赶上进度的迁移:

    supabase db pull

    如果你的历史是基于旧版差异构建的,它不会提到旧版引擎没有跟踪的对象,比如评论、域、角色和发布成员。这次首次拉取会在一次赶上迁移中捕获它们。你的远程数据库已经有这些对象,所以接受提示,将迁移记录为已应用,并像对待其他生成的迁移文件一样查看它。如果你的基线来自旧版引擎的 pg_dump 路径,它已经包含这些对象,这次拉取会显示“未发现架构更改”。在这种情况下,没有需要提交的东西。详见 清理生成的迁移。

  4. 在从声明性文件生成迁移时,将 supabase db diff 替换为 supabase db schema declarative sync,包括 shell 脚本、CI 作业和 AI 提示文件,例如 examples/prompts/declarative-database-schema.md。你不再需要在生成之前运行 supabase stop。如果 CLI 没有生成你的 schema 树,请参见 采用现有的 schema 树,了解在第一次 sync 上运行的两个检查。

  5. 本地验证完整迁移链:

    supabase db reset
  6. 可选地,将 supabase db diff --strict-coverage 添加到 CI,这样未跟踪的对象会导致任务失败,而不是产生警告。请参见 管理环境。

如果你通过 GitHub 集成 部署,每次迁移都会在事务中运行分支,并且不会遵循 -- pg-delta: transaction=false 指令。带有该指令的迁移会在 supabase db push 下应用,但在分支部署时会失败。

🌐 If you deploy through the GitHub integration, branching runs every migration inside a transaction and doesn't honor the -- pg-delta: transaction=false directive. A migration that carries it applies with supabase db push but fails when branching deploys it.

要返回,请在 [experimental.pgdelta] 下设置 enabled = false,或者使用上面的每个命令标志进行单次运行。由 pg-delta 已生成的迁移是普通 SQL,在任一引擎上都能继续使用。

🌐 To go back, set enabled = false under [experimental.pgdelta], or use the per-command flags above for a single run. Migrations already generated by pg-delta are plain SQL and keep working on either engine.