mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 01:15:03 +03:00
docs(cli): update local development workflow docs for pg-delta default diffing (#49280)
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Docs update. ## What is the current behavior? Linear: [CLI-1618](https://linear.app/supabase/issue/CLI-1618/update-cli-workflow-docs-for-pg-delta-default-diffing) Four docs pages lag the shipped CLI behavior now that `pg-delta` is the default diff engine for projects created by a recent `supabase init`: - **CLI workflows** claims `db diff` compares `supabase/schemas/` against migrations. Under `pg-delta`, declarative files are never the `db diff` baseline (and `[db.migrations].schema_paths` no longer changes it) — the declarative flow goes through `supabase db schema declarative sync`. The cleanup guidance describes `migra`-era output. - **Declarative database schemas** teaches the old `db diff -f` + `schema_paths` flow throughout, and its known-caveats list is the `migra` issue list. - **Managing environments** still presents `--use-migra` as an "experimental flag" for a "more concise" diff — inverted now. - **Backup and restore (migrating within Supabase)** and the CLI workflows guide both steer users to `db diff`/`db pull` with `--schema auth,storage`. Under `pg-delta`, `--schema` layers an extra exclude policy on top of the Supabase profile: it can only narrow a diff, never re-include managed schemas, and managed-schema selections can even fail closed (e.g. `--schema auth` when a trigger function lives in `public`). Unfiltered diffs are the supported path. ## What is the new behavior? All claims verified against the CLI source at current `develop` — including supabase/cli#6300, which upgraded the engine to `@supabase/pg-delta` 1.0.0-alpha.46 — against the pinned pg-delta package source (profile rules, format defaults, coverage doc), and against a live dogfood run of the documented workflows on `develop` `38f31b4` (two OSS corpus projects, warm shadow cache). - **`cli-workflows.mdx`**: adds a "Which diff engine you're on" note (`pg-delta` for new `supabase init` projects, `migra` for existing ones until they opt in by adding `[experimental.pgdelta] enabled = true`; per-run fallbacks `--use-migra` on `db diff` / `--diff-engine migra` on `db pull`); corrects `db pull` and `db diff` mechanics (shadow built from migrations vs. live database; the baseline history record is offered, not unconditional); switches the declarative flow to `supabase db schema declarative sync`; reworks the cleanup section around pg-delta output (uppercase keywords at max width 180, `format_options`, per-unit migration files with numeric segment suffixes, the `-- pg-delta: transaction=false` directive on genuinely non-transactional files, engine-neutral grant/revoke review guidance, coverage warnings + `--strict-coverage`); documents what pg-delta captures in managed schemas (user triggers, RLS policies on `auth` tables and on `storage.objects`/`storage.buckets`/`realtime.messages`) versus what it doesn't; adds key-command rows for the declarative commands and troubleshooting entries (`db pull` non-zero exit when in sync, the `schema_paths` warning, `PGDELTA_DEBUG=1` bundles under `supabase/.temp/pgdelta/v2/debug/`). - **`declarative-database-schemas.mdx`**: swaps `db diff -f` for `db schema declarative sync -f` throughout; replaces lexicographic/`schema_paths` ordering guidance with automatic dependency ordering and the `generate` export layout (`_cluster/`, reserved `_custom/`); bootstraps from production via `db schema declarative generate --linked` (explicit target + `--overwrite` in scripts) and refreshes via `db pull --declarative`; rewrites known caveats for pg-delta (DML including storage buckets, untracked object kinds + the `_custom/` escape hatch, managed schemas, extension-managed objects, and the two gates when adopting an existing schema tree: `[experimental.webhooks]` for `pg_net` migrations and declaring the tree's extensions) keeping the `migra` workflow and issue list under a legacy section for projects that haven't enabled it. - **`managing-environments.mdx`**: frames the verbose grant sample as legacy-engine output, notes that generated migrations can include grant statements on any engine, describes `--use-migra` as a single-run fallback, and adds a `db diff --strict-coverage` CI step. - **`backup-restore.mdx`**: replaces `db diff --linked --schema auth,storage` with a plain `db diff --linked` on `pg-delta` (keeping the `--schema auth,storage` form for the legacy engine) and explains what the engine includes (user triggers on managed tables, user RLS policies on `auth`, `storage.objects`/`storage.buckets`/`realtime.messages`) and what must be recreated manually. - **New `diff-engines.mdx` page** (from #49889): the single home for how the engine is selected, a behavior matrix for `pg-delta` versus `migra`, the per-command fallback flags, a procedure for switching an existing project (the first `db pull` after enabling may write a catch-up migration), and how to go back with `enabled = false`. Registered in navigation. A shared `diff_engine_check` partial replaces the inline engine parentheticals across seven pages, and a `managed_schemas_diff_capture` partial carries the managed-schema capture rules. - **CLI reference (`cli_v1_commands.yaml`, `cli_v1_config.yaml`)**: `db pull`, `db schema declarative sync`/`generate` flags and descriptions, `experimental.pgdelta.*` and `db.migrations.schema_paths` config keys, and the `db diff` description updated to describe both engines. Note that `cli_v1_commands.yaml` is generated from the CLI repo; [supabase/cli#6557](https://github.com/supabase/cli/pull/6557) carries the matching `db pull` example and overlay text so the next publish keeps it. - **`examples/prompts/declarative-database-schema.md`**: rewritten for the `db schema declarative sync` flow, with the `[experimental.pgdelta]` prerequisite. ## Additional context The first draft was written against pg-delta 1.0.0-alpha.42. supabase/cli#6300 (engine upgrade to alpha.46) then changed two documented behaviors, both reflected here: generated SQL now defaults to uppercase pretty-printed keywords, and user RLS policies on `storage.objects`/`storage.buckets`/`realtime.messages` are included via the engine's `SUPABASE_USER_POLICY_SURFACES` allowlist. A follow-up dogfood run on `develop` `38f31b4` then falsified three more claims (pg-delta emits no grant noise, `_schema_changes`/`_after_enum_values` multi-file names, directive on every split file), all corrected in the last commit. **Update (Sep 14 to 17):** [#49889](https://github.com/supabase/supabase/pull/49889) and [#50220](https://github.com/supabase/supabase/pull/50220) were merged into this branch, so this PR now carries the full stack. #50220 corrected the `schema_paths` warning wording (the CLI warns only when the setting lists paths), added `auth` RLS policies to the managed-schema partial, and described the migra initial pull accurately (the `pg_dump` skips managed schemas and the migra diff pass that follows appends the trigger and policy changes). It also reframed `pg-delta` as the default for every project ahead of supabase/cli#6391. That plan changed: no breaking default flip before Select, so [#50332](https://github.com/supabase/supabase/pull/50332) restores the opt-in framing (`pg-delta` requires `[experimental.pgdelta] enabled = true`, which `supabase init` writes for new projects) and also resolves the four CodeRabbit findings from the latest review round. Two claims are pending confirmation from the owning teams: that branching runs every migration in a transaction and ignores the `-- pg-delta: transaction=false` directive, and the `--db-url` pooler-versus-direct connection advice, which currently disagrees with the CLI's own `db pull` docs. Stale spots found in the CLI repo's own docs while verifying (out of scope here, worth follow-ups): four `SIDE_EFFECTS.md` files still claim lowercase output, `docs/supabase/db/diff.md` still lists `migra`-era "known failure cases" that alpha.46 fully models, the `supabase init` template's commented `format_options` example shows `maxWidth: 80` against an actual default of 180, and the CLI upgrade recipe appends `--experimental` even when the config already enables pg-delta. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01SUuaVmXLRbV6tZjzhka3cp <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Clarified `pg-delta` and legacy `migra` behavior, configuration, and switching guidance. * Expanded declarative schema workflows, including synchronization, migration generation, baselines, deployment, and legacy-engine support. * Documented managed schemas, permissions, extensions, transaction handling, dependency ordering, and troubleshooting. * Added guidance for strict coverage checks, output directories, non-interactive workflows, and declarative pull modes. * Added a dedicated diff engines guide and updated CLI navigation, backup and restore, branching, deployment, and CI documentation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Wen Bo Xie <wenbox323@gmail.com>
This commit is contained in:
19 files changed
+556
-190
No files matched your search
@@ -2537,6 +2537,10 @@ export const local_development: NavMenuConstant = {
|
||||
name: 'Declarative database schemas',
|
||||
url: '/guides/local-development/declarative-database-schemas' as `/${string}`,
|
||||
},
|
||||
{
|
||||
name: 'Diff engines',
|
||||
url: '/guides/local-development/diff-engines' as `/${string}`,
|
||||
},
|
||||
{
|
||||
name: 'Seeding your database',
|
||||
url: '/guides/local-development/seeding-your-database' as `/${string}`,
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
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](/docs/guides/local-development/diff-engines) for how the two differ and how to switch.
|
||||
@@ -0,0 +1 @@
|
||||
Under the `pg-delta` engine, the diff excludes platform objects in Supabase-managed schemas such as `auth` and `storage`. It captures your customizations on top of them, such as triggers on managed tables, RLS policies on any table in `auth`, and RLS policies on `storage.objects`, `storage.buckets`, and `realtime.messages`. A trigger counts as yours only when its function lives outside the managed schemas (for example, a trigger on `auth.users` calling a function in `public`). A trigger whose function lives inside `auth` or `storage` is excluded, even if you created the function. The diff also skips other objects you create inside these schemas, such as your own functions or indexes.
|
||||
@@ -49,7 +49,7 @@ No. The GitHub integration and CLI-based deployments work on all plans. Branchin
|
||||
|
||||
### What gets deployed?
|
||||
|
||||
Database migrations in your `supabase/` directory, plus Edge Functions and storage buckets that are declared in `supabase/config.toml`. Other local configuration files (such as API or Auth settings) are ignored by default. See the [local development guide](/docs/guides/local-development) for details on the directory structure.
|
||||
Database migrations in your `supabase/` directory, plus Edge Functions and Storage buckets that are declared in `supabase/config.toml`. If you use [declarative schemas](/docs/guides/local-development/declarative-database-schemas), only the generated migrations are deployed and not the `supabase/schemas/` files themselves. On preview branches, `config.toml` settings such as `[api]` and `[auth]` are also applied to the branch project by default. On persistent branches, including your production branch, those settings are skipped unless you opt in with a `[remotes]` block for that project. See the [local development guide](/docs/guides/local-development) for details on the directory structure.
|
||||
|
||||
### Can you use your own CI/CD pipeline?
|
||||
|
||||
|
||||
@@ -97,6 +97,10 @@ A comment is added to your PR with the deployment status of your preview branch.
|
||||
|
||||
The migrations in the `migrations` subdirectory of your Supabase directory are automatically run when the branch is created. Each later commit runs only the migrations that haven't been applied yet.
|
||||
|
||||
If your project uses [declarative schemas](/docs/guides/local-development/declarative-database-schemas), the files in `supabase/schemas/` are not applied by branching. Run `supabase db schema declarative sync` to generate a migration from your schema changes, and commit the generated migration alongside your schema files.
|
||||
|
||||
Branching runs each migration file inside a single transaction and does not honor the `-- pg-delta: transaction=false` directive. A migration that can't run in a transaction (for example, one that uses `create index concurrently`, or a [`pg-delta`](/docs/guides/local-development/diff-engines) file that carries the directive) applies with `supabase db push` but fails when branching deploys it.
|
||||
|
||||
If you want to rerun existing migrations, reset the branch from the Supabase dashboard to start from scratch. Note that existing data on your branch will also be dropped by a reset.
|
||||
|
||||
### Seeding
|
||||
|
||||
@@ -45,6 +45,8 @@ When a preview branch is merged into the production branch, it creates a schema
|
||||
|
||||
These conflicts can be resolved in the same way as normal Git Conflicts: merge or rebase from the production Git branch to the preview Git branch. Since migrations are applied sequentially, ensure that migration files are timestamped correctly after the rebase. Changes that build on top of earlier changes should always have later timestamps.
|
||||
|
||||
If you manage your schema with [declarative schema files](/docs/guides/local-development/declarative-database-schemas), resolve the drift in the schema files instead. Delete the migrations your branch generated, then run `supabase db schema declarative sync` to regenerate them. The regenerated migration gets a new timestamp, so it orders after existing migrations without renaming files by hand.
|
||||
|
||||
### Changing production branch
|
||||
|
||||
You cannot change which project branch serves as the production branch — the base project that all branches are created from will always remain the production branch. However, you can update which GitHub branch is linked to your production branch. To do this, go to the [Integrations page](/dashboard/project/_/settings/integrations) and change the production branch name.
|
||||
@@ -93,6 +95,8 @@ mv 20240101000000_old.sql 20240102000000_old.sql
|
||||
supabase db reset
|
||||
```
|
||||
|
||||
Within a single migration generated on the [`pg-delta`](/docs/guides/local-development/diff-engines) engine (`supabase db diff` or `db schema declarative sync`), you don't need to reorder statements by hand, because the engine orders them by dependency. Migrations generated separately, such as on two branches that later merge, still need correct relative timestamps, so rename or regenerate them as shown above. A single sync can write split files that share a name (`_1`/`_2` suffixes) with timestamps one second apart. The CLI applies them in timestamp order, so renaming one file of a split pair in a way that changes that order breaks the sequence. Regenerate the migration instead. See [Cleaning up generated migrations](/docs/guides/local-development/cli-workflows#cleaning-up-generated-migrations).
|
||||
|
||||
## Connection issues
|
||||
|
||||
### Cannot connect to preview branch
|
||||
|
||||
@@ -359,6 +359,8 @@ You can develop with branches using either local or remote development workflows
|
||||
5. Commit and push to GitHub
|
||||
6. Open a pull request to create a preview branch
|
||||
|
||||
If your project uses [declarative schemas](/docs/guides/local-development/declarative-database-schemas), edit your files in `supabase/schemas/` and generate migrations with `supabase db schema declarative sync` instead of `supabase db diff`, which on `pg-delta` never uses your schema files as its baseline. If your project hasn't enabled `pg-delta`, follow [Declarative schemas on the legacy `migra` engine](/docs/guides/local-development/declarative-database-schemas#declarative-schemas-on-the-legacy-migra-engine) instead. Branching applies only committed migration files, so commit the schema files and the generated migrations together.
|
||||
|
||||
### Remote development workflow
|
||||
|
||||
1. Create a preview branch in the Supabase dashboard
|
||||
|
||||
@@ -200,6 +200,16 @@ You should now see the `employees` table, along with your seed data in the Dashb
|
||||
|
||||
This workflow is great if you know SQL and are comfortable creating tables and columns. If not, you can still use the Dashboard to create tables and columns, and then use the CLI to diff your changes and create migrations.
|
||||
|
||||
The SQL that `db diff` generates depends on your project's diff engine.
|
||||
|
||||
<$Partial path="diff_engine_check.mdx" />
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
If you'd rather declare the state you want your database to be in and have migrations generated for you, manage your schema declaratively instead. On `pg-delta`, edit files in `supabase/schemas/` and generate migrations with `supabase db schema declarative sync`. Don't use `db diff` to generate migrations from declarative files on that engine, because it never uses `supabase/schemas/` as its baseline. On the legacy `migra` engine, `db schema declarative sync` won't run and `db diff` does read `supabase/schemas/`, so follow [Declarative schemas on the legacy `migra` engine](/docs/guides/local-development/declarative-database-schemas#declarative-schemas-on-the-legacy-migra-engine) instead. See [Declarative database schemas](/docs/guides/local-development/declarative-database-schemas).
|
||||
|
||||
</Admonition>
|
||||
|
||||
<Admonition type="caution">
|
||||
|
||||
Only use the Dashboard to make schema changes on your **local** database, then capture them with `supabase db diff`. Making schema changes directly on your **remote** database (via the SQL editor or Table Editor) bypasses the migration history and will cause `db push` to fail with sync errors. Once you're using migrations, all schema changes to your remote database should go through migration files only.
|
||||
@@ -473,6 +483,19 @@ supabase db pull
|
||||
|
||||
This creates a new migration file capturing the current remote schema. Commit it to git, then follow the standard workflow going forward.
|
||||
|
||||
What `db pull` captures in managed schemas depends on your project's diff engine.
|
||||
|
||||
<$Partial path="diff_engine_check.mdx" />
|
||||
|
||||
On `pg-delta`, a plain `supabase db pull` captures your customizations automatically, such as a trigger on `auth.users` that calls a function in `public`, or RLS policies on `storage.objects`. A trigger whose function lives inside `auth` or `storage` is excluded even if you created it, so deliver it through a versioned migration. On the legacy `migra` engine, the initial pull's `pg_dump` skips those schemas, but the diff pass that follows appends your triggers and RLS policies there to the same migration, and later pulls diff them too. Older CLI versions excluded `auth` and `storage` entirely and printed a message saying so. If you see that message, capture existing customizations once with explicit pulls:
|
||||
|
||||
```bash name=Terminal
|
||||
supabase db pull --schema auth
|
||||
supabase db pull --schema storage
|
||||
```
|
||||
|
||||
See [Diff engines](/docs/guides/local-development/diff-engines) for what each engine captures in managed schemas.
|
||||
|
||||
### Step 3: If the migration history table is wrong
|
||||
|
||||
If a migration shows as missing in the remote history table but the schema change is already there (for example, it was applied manually), you can mark it as applied without re-running it:
|
||||
|
||||
@@ -112,43 +112,17 @@ Next, generate a schema diff by running the following command:
|
||||
supabase db diff -f new_employee
|
||||
```
|
||||
|
||||
You should see that a new file `supabase/migrations/<timestamp>_new_employee.sql` is created. Open the file and verify that the generated DDL statements are the same as below.
|
||||
You should see that a new file `supabase/migrations/<timestamp>_new_employee.sql` is created. Open the file and review the generated DDL statements. Expect a `create table` statement for `public.employees`, often followed by `grant` statements for the default roles. The exact SQL depends on your project's diff engine.
|
||||
|
||||
```sql
|
||||
-- This script was generated by the Schema Diff utility in pgAdmin 4
|
||||
-- For the circular dependencies, the order in which Schema Diff writes the objects is not very sophisticated
|
||||
-- and may require manual changes to the script to ensure changes are applied in the correct order.
|
||||
-- Please report an issue for any failure with the reproduction steps.
|
||||
<$Partial path="diff_engine_check.mdx" />
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.employees
|
||||
(
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
|
||||
name text COLLATE pg_catalog."default",
|
||||
CONSTRAINT employees_pkey PRIMARY KEY (id)
|
||||
)
|
||||
|
||||
TABLESPACE pg_default;
|
||||
|
||||
ALTER TABLE IF EXISTS public.employees
|
||||
OWNER to postgres;
|
||||
|
||||
GRANT ALL ON TABLE public.employees TO anon;
|
||||
|
||||
GRANT ALL ON TABLE public.employees TO authenticated;
|
||||
|
||||
GRANT ALL ON TABLE public.employees TO postgres;
|
||||
|
||||
GRANT ALL ON TABLE public.employees TO service_role;
|
||||
```
|
||||
|
||||
You may notice that the auto-generated migration script is more verbose than the manually written one.
|
||||
This is because the default schema diff tool does not account for default privileges added by the initial schema.
|
||||
This auto-generated migration script is usually more verbose than the manually written one. Both engines treat permissions as part of the schema state, so generated migrations can include `GRANT` and `REVOKE` statements you didn't write. If you haven't changed permissions and the roles already hold those privileges on the target database, these lines are safe to remove.
|
||||
|
||||
Commit the new migration script to git and you are ready to deploy.
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
Alternatively, you may pass in the `--use-migra` experimental flag to generate a more concise migration using [`migra`](https://github.com/djrobstep/migra).
|
||||
To generate the diff with the legacy [`migra`](https://github.com/djrobstep/migra) engine for a single run, pass the `--use-migra` flag.
|
||||
|
||||
Without the `-f` file flag, the output is written to stdout by default.
|
||||
|
||||
@@ -225,6 +199,9 @@ jobs:
|
||||
- name: Start Supabase local development setup
|
||||
run: supabase db start
|
||||
|
||||
- name: Verify schema coverage
|
||||
run: supabase db diff --strict-coverage
|
||||
|
||||
- name: Verify generated types are checked in
|
||||
run: |
|
||||
supabase gen types typescript --local > types.gen.ts
|
||||
@@ -235,6 +212,8 @@ jobs:
|
||||
fi
|
||||
```
|
||||
|
||||
The `supabase db diff --strict-coverage` step applies to projects on the `pg-delta` engine. It fails the job when `pg-delta` finds schema objects it doesn't track, instead of reporting them as warnings. Remove this step if your project uses the legacy `migra` engine, where the flag has no effect. See [Diff engines](/docs/guides/local-development/diff-engines).
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="staging" label="staging.yaml">
|
||||
|
||||
@@ -345,7 +324,7 @@ The `release` job applies all new migration scripts merged in `supabase/migratio
|
||||
|
||||
When setting up a new staging project, you might need to sync the initial schema with migrations previously applied to the production project.
|
||||
|
||||
One way is to leverage the Release workflow:
|
||||
One way is to use the Release workflow:
|
||||
|
||||
- Create a new branch `develop` and choose `main` as the branch source
|
||||
- Push the `develop` branch to GitHub
|
||||
|
||||
@@ -151,7 +151,7 @@ The Supabase CLI is a tool that enables developers to run Supabase services loca
|
||||
|
||||
- Setting up and managing local development environments
|
||||
- Generating TypeScript types for your database schema
|
||||
- Handling database migrations
|
||||
- Handling [database migrations](/docs/guides/local-development/database-migrations) and [declarative database schemas](/docs/guides/local-development/declarative-database-schemas)
|
||||
- Managing environment variables and secrets
|
||||
- Deploying your project to the Supabase platform
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ You need the Supabase CLI installed and a Docker-compatible runtime running. If
|
||||
|
||||
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](https://supabase.com) or a proper self-hosted setup for anything beyond that.
|
||||
|
||||
<Admonition type="note" label="`supabase` vs. `npx supabase`">
|
||||
<Admonition type="note" title="`supabase` vs. `npx supabase`">
|
||||
|
||||
How you invoke the CLI depends on how you installed it:
|
||||
|
||||
@@ -29,13 +29,13 @@ Every example in this guide is written as `supabase <command>`. Translate it to
|
||||
|
||||
</Admonition>
|
||||
|
||||
<Admonition type="note" label="Starting from a template">
|
||||
<Admonition type="note" title="Starting from a template">
|
||||
|
||||
If you want a working project to explore rather than an empty one, `supabase bootstrap` scaffolds a starter application (Next.js, Flutter, and more) with schema, migrations, and config already wired up. It's an alternative entry point to `supabase init` when starting a new project from scratch.
|
||||
|
||||
</Admonition>
|
||||
|
||||
## The `./supabase` directory
|
||||
## The `./supabase` directory [#the-supabase-directory]
|
||||
|
||||
After `supabase init`, your project contains a `./supabase` directory. Here's what goes in it and what to commit:
|
||||
|
||||
@@ -49,12 +49,20 @@ After `supabase init`, your project contains a `./supabase` directory. Here's wh
|
||||
|
||||
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](/docs/guides/local-development/managing-config).
|
||||
|
||||
<Admonition type="note" label="Local vs. remote targets">
|
||||
<Admonition type="note" title="Local vs. remote targets">
|
||||
|
||||
Many database commands accept `--local` and `--linked` flags to choose what they act on. The defaults are not the same across commands: `db diff` and `db reset` default to `--local`, while `db pull`, `db push`, and `db dump` default to `--linked`. When in doubt, pass the flag explicitly.
|
||||
|
||||
</Admonition>
|
||||
|
||||
## Which diff engine you're on [#pg-delta]
|
||||
|
||||
`db diff`, `db pull`, and the `db schema declarative` commands generate SQL with a diff engine. The CLI ships two. [`pg-delta`](https://github.com/supabase/pg-toolbelt/tree/main/packages/pg-delta) is the engine for projects created with a recent `supabase init`, and [`migra`](https://github.com/djrobstep/migra) is the legacy engine.
|
||||
|
||||
<$Partial path="diff_engine_check.mdx" />
|
||||
|
||||
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](/docs/guides/local-development/diff-engines).
|
||||
|
||||
## Move an existing project to local development
|
||||
|
||||
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.
|
||||
@@ -93,30 +101,29 @@ This tells the CLI which remote project to connect to for `db pull`, `db push`,
|
||||
supabase db pull
|
||||
```
|
||||
|
||||
This connects to your remote database, dumps the entire schema, and saves it as a migration file:
|
||||
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
|
||||
```
|
||||
|
||||
This initial migration is your baseline. It represents the current state of your database, and all future changes build on top of it. `db pull` also records this migration as already applied in the remote migration history (the `supabase_migrations.schema_migrations` table), so a later `db push` won't try to reapply it.
|
||||
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.
|
||||
|
||||
<Admonition type="caution" label="Review the generated migration">
|
||||
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 pull` diffs your remote database against the CLI's default local stack, so the generated file can include statements you didn't expect. A common example is `DROP EXTENSION pg_net;`, emitted when your remote project has an extension disabled that the local stack enables by default. These statements apply silently on `db reset` and change your local schema, so read the file before committing it. See [Cleaning up generated migrations](#cleaning-up-generated-migrations) for what to look for.
|
||||
When connecting with `--db-url` for `db pull` or `db diff`, prefer the direct connection (`db.<project-ref>.supabase.co:5432`) so `pg-delta` can read the full catalog. Direct connections require IPv6 or the IPv4 add-on, so on an IPv4-only network use the session pooler instead. Don't use the transaction pooler for these commands. For `db dump` and `psql`, the session pooler is the safe default.
|
||||
|
||||
<Admonition type="caution" title="Review the generated migration">
|
||||
|
||||
The generated file can include statements you didn't expect. The engine excludes Supabase platform-managed schemas, roles, and a small set of platform extensions, but extensions you enable yourself (`pg_net`, `pg_cron`, `pgcrypto`, and others) are diffed like any other object. A `DROP EXTENSION "pg_net";` appears when your local configuration or migrations enable the extension and the remote project doesn't have it. These statements apply silently on `db reset` and change your local schema, so read the file before committing it. See [Cleaning up generated migrations](#cleaning-up-generated-migrations) for what to look for.
|
||||
|
||||
</Admonition>
|
||||
|
||||
<Admonition type="note">
|
||||
<Admonition type="note" title="Customizations in the `auth` and `storage` schemas">
|
||||
|
||||
If you also use Supabase Auth or Storage and have customized their schemas, pull them separately:
|
||||
<$Partial path="managed_schemas_diff_capture.mdx" />
|
||||
|
||||
```bash
|
||||
supabase db pull --schema auth -f pull-auth-schema
|
||||
supabase db pull --schema storage -f pull-storage-schema
|
||||
```
|
||||
|
||||
These schemas are managed by Supabase and typically don't need to be pulled unless you've made custom modifications.
|
||||
Manage those objects with [hand-written migrations](/docs/guides/deployment/database-migrations). On `pg-delta`, omit `--schema` on later pulls. The flag only narrows the diff further and can't add managed objects back, so listing `auth` alone would drop a trigger whose function lives in `public`. On the legacy `migra` engine, the initial pull's `pg_dump` skips these schemas, but the diff pass that follows appends your triggers and RLS policies in them to the same migration. If an older CLI prints a message that `auth` and `storage` were excluded, run `supabase db pull --schema auth,storage` once.
|
||||
|
||||
</Admonition>
|
||||
|
||||
@@ -138,7 +145,7 @@ Review and clean up the dump before committing. Remove production user data, sec
|
||||
|
||||
**Option B: Write seed data by hand** (recommended for most projects):
|
||||
|
||||
Create `supabase/seed.sql` with INSERT statements that set up a useful local development state: a few test users, sample data, and so on. This is often better than dumping production data because you control exactly what's in it.
|
||||
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.
|
||||
|
||||
For more on organizing seed files, glob patterns, and generating realistic data, see [Seeding your database](/docs/guides/local-development/seeding-your-database).
|
||||
|
||||
@@ -160,9 +167,9 @@ git commit -m "add supabase local development setup"
|
||||
|
||||
Your project now has a fully reproducible local development environment.
|
||||
|
||||
<Admonition type="note" label="What about declarative schemas?">
|
||||
<Admonition type="note" title="What about declarative schemas?">
|
||||
|
||||
For an existing project, the pulled migration already serves as your schema baseline. You don't need to also create a `schemas/` directory, because that would mean maintaining two representations of the same schema. If you want to adopt declarative schemas later, see [Declarative database schemas](/docs/guides/local-development/declarative-database-schemas). For day-to-day changes going forward, see [The daily workflow](#the-daily-workflow) below.
|
||||
For an existing project, the pulled migration is already your schema baseline. You don't need to also create a `schemas/` directory, because that would mean maintaining two representations of the same schema. If you want to adopt declarative schemas later, `supabase db schema declarative generate` bootstraps the `supabase/schemas/` directory (or the directory set by `experimental.pgdelta.declarative_schema_path`) from your live database. See [Declarative database schemas](/docs/guides/local-development/declarative-database-schemas). For day-to-day changes, see [The daily workflow](#the-daily-workflow).
|
||||
|
||||
</Admonition>
|
||||
|
||||
@@ -215,10 +222,12 @@ create policy "Users can create their own todos"
|
||||
Then generate a migration from it:
|
||||
|
||||
```bash
|
||||
supabase db diff -f initial-schema
|
||||
supabase db schema declarative sync -f initial-schema
|
||||
```
|
||||
|
||||
This compares your declared schema against the current (empty) database and generates a migration file in `supabase/migrations/`. For the full declarative workflow, including managing views and functions, ordering schema files, and known caveats, see [Declarative database schemas](/docs/guides/local-development/declarative-database-schemas).
|
||||
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.
|
||||
|
||||
The `db schema declarative` commands require [`pg-delta`](/docs/guides/local-development/diff-engines), 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](/docs/guides/local-development/declarative-database-schemas).
|
||||
|
||||
**Option B: Write the migration directly**
|
||||
|
||||
@@ -283,15 +292,19 @@ Which approach you use is a project-level decision, set when you first created y
|
||||
>
|
||||
<TabPanel id="declarative" label="Declarative schemas">
|
||||
|
||||
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](/docs/guides/local-development/declarative-database-schemas#declarative-schemas-on-the-legacy-migra-engine).
|
||||
|
||||
1. Edit your schema file(s) in `supabase/schemas/` (add a table, a column, a policy, etc.)
|
||||
2. Generate a migration: `supabase db diff -f add-due-date-to-todo`
|
||||
3. Review the generated migration file. See [Cleaning up generated migrations](#cleaning-up-generated-migrations)
|
||||
2. Generate a migration: `supabase db schema declarative sync -f add-due-date-to-todo`
|
||||
3. Review the generated migration file(s). See [Cleaning up generated migrations](#cleaning-up-generated-migrations)
|
||||
4. Verify the full chain: `supabase db reset`
|
||||
5. Commit the schema file **and** the migration together
|
||||
5. Commit the schema file and the migration(s) together
|
||||
|
||||
<Admonition type="caution">
|
||||
|
||||
`db diff` compares your `supabase/schemas/` files against your existing migrations; it does **not** read the live local database. Changes you make directly in Studio or via SQL are ignored, so `db diff` reports "No schema changes found" and silently drops them. Always edit the schema files, then diff.
|
||||
`db schema declarative sync` compares your `supabase/schemas/` files against your existing migrations. It does not read the live local database. Changes you make directly in Studio or via SQL are invisible to it, so it reports "No schema changes found" and silently drops them. Always edit the schema files, then sync.
|
||||
|
||||
Don't use `db diff` to generate migrations from declarative files. Under `pg-delta`, `db diff` never uses `supabase/schemas/` as its baseline. The old `[db.migrations].schema_paths` setting no longer changes that, and the CLI warns when the setting lists any paths. Remove it from `config.toml`.
|
||||
|
||||
</Admonition>
|
||||
|
||||
@@ -304,7 +317,7 @@ Which approach you use is a project-level decision, set when you first created y
|
||||
supabase db diff -f add-due-date-to-todo
|
||||
```
|
||||
|
||||
This captures your UI changes as a migration file. This works only when your project has **no** declarative files in `supabase/schemas/`: `db diff` then compares the live local database against your migrations. If you use declarative schemas, don't edit through Studio expecting `db diff` to catch it - see the **Declarative schemas** tab.
|
||||
This captures your UI changes as a migration file. `db diff` compares the live local database against a shadow database built from your migrations, so anything you changed through Studio (or any SQL you ran) shows up in the diff. If you use declarative schemas, this leaves your schema files stale. Make changes by editing the files instead, per the **Declarative schemas** tab.
|
||||
|
||||
**If you prefer to write SQL directly:**
|
||||
|
||||
@@ -386,7 +399,7 @@ If a dev or staging remote drifts or gets into a messy state, you can wipe it an
|
||||
supabase db reset --linked
|
||||
```
|
||||
|
||||
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, then replays every local migration in order. Add `--include-seed` to reload seed data as well.
|
||||
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.
|
||||
|
||||
<Admonition type="danger">
|
||||
|
||||
@@ -398,61 +411,69 @@ For multi-environment setups with CI/CD (feature branches, staging, production),
|
||||
|
||||
## Key commands at a glance
|
||||
|
||||
| Command | What it does |
|
||||
| -------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| `supabase init` | Creates `./supabase/config.toml` |
|
||||
| `supabase start` | Starts the local stack, applies migrations + seed |
|
||||
| `supabase stop` | Stops the local stack (data persists until `db reset`) |
|
||||
| `supabase db reset` | Destroys local DB, applies all migrations + seed from scratch |
|
||||
| `supabase db reset --linked` | Destroys the **linked remote** DB and rebuilds it from local migrations (destructive; dev/staging only) |
|
||||
| `supabase db diff -f <name>` | Generates a migration by diffing current DB state against a shadow database |
|
||||
| `supabase db pull` | Pulls remote schema into a new local migration file |
|
||||
| `supabase db push` | Applies pending local migrations to the remote database |
|
||||
| `supabase db dump` | Exports remote DB schema (or `--data-only` for data) via `pg_dump` |
|
||||
| `supabase migration new <name>` | Creates an empty migration file |
|
||||
| `supabase migration list` | Compares local migrations against remote migration history |
|
||||
| `supabase gen types --lang typescript` | Generates TypeScript types from your database schema |
|
||||
| `supabase link --project-ref` | Connects local project to a remote Supabase project |
|
||||
| `supabase login` | Authenticates with the Supabase platform |
|
||||
| Command | What it does |
|
||||
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
||||
| `supabase init` | Creates `./supabase/config.toml` |
|
||||
| `supabase start` | Starts the local stack, applies migrations + seed |
|
||||
| `supabase stop` | Stops the local stack (data persists until `db reset`) |
|
||||
| `supabase db reset` | Destroys local DB, applies all migrations + seed from scratch |
|
||||
| `supabase db reset --linked` | Destroys the **linked remote** DB and rebuilds it from local migrations + seed (destructive, dev/staging only) |
|
||||
| `supabase db diff -f <name>` | Generates a migration by diffing a live database (local by default) against a shadow built from your migrations |
|
||||
| `supabase db schema declarative sync` | Diffs `supabase/schemas/` against your migrations and writes the difference as new migration file(s) |
|
||||
| `supabase db schema declarative generate` | Exports a live database into declarative schema files under `supabase/schemas/` |
|
||||
| `supabase db pull` | Pulls remote schema into a new local migration file |
|
||||
| `supabase db pull --declarative` | Updates `supabase/schemas/` from the remote database instead of creating a migration. `pg-delta` projects only |
|
||||
| `supabase db push` | Applies pending local migrations to the remote database |
|
||||
| `supabase db dump` | Exports remote DB schema (or `--data-only` for data) via `pg_dump` |
|
||||
| `supabase migration new <name>` | Creates an empty migration file |
|
||||
| `supabase migration list` | Compares local migrations against remote migration history |
|
||||
| `supabase gen types --lang typescript` | Generates TypeScript types from your database schema |
|
||||
| `supabase link --project-ref` | Connects local project to a remote Supabase project |
|
||||
| `supabase login` | Authenticates with the Supabase platform |
|
||||
|
||||
For the full command reference and every flag, see the [CLI reference](/docs/reference/cli).
|
||||
|
||||
## Cleaning up generated migrations
|
||||
|
||||
When `supabase db diff` generates a migration, it may include statements that are technically correct but noisy. Review every generated migration before committing.
|
||||
When `supabase db diff` or `db schema declarative sync` generates a migration, review it before committing.
|
||||
|
||||
### Grants
|
||||
### What `pg-delta` output looks like
|
||||
|
||||
You may see lines like:
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
```sql
|
||||
GRANT MAINTAIN, REFERENCES, TRIGGER, TRUNCATE ON public.todos TO anon;
|
||||
GRANT MAINTAIN, REFERENCES, TRIGGER, TRUNCATE ON public.todos TO authenticated;
|
||||
GRANT MAINTAIN, REFERENCES, TRIGGER, TRUNCATE ON public.todos TO service_role;
|
||||
-- pg-delta: transaction=false
|
||||
```
|
||||
|
||||
These appear because the diff tool treats permissions as part of the schema state. For tables in the `public` schema, these grants are applied by default and the lines are redundant. They're harmless, but if you want clean migrations, you can remove them. Be consistent across your team about whether you keep or remove them.
|
||||
`db reset`, `db push`, and `migration up` honor it by running the file's statements without a wrapping transaction. Keep the line. The CLI detects `create index concurrently` on its own and runs it standalone even without the directive, but other statements that can't run in a transaction depend on it. The directive also changes what happens on failure. Without a wrapping transaction, a failed statement leaves the earlier statements in the file applied.
|
||||
|
||||
### Revoke/re-grant patterns
|
||||
|
||||
Sometimes a diff produces:
|
||||
|
||||
```sql
|
||||
REVOKE ALL ON TABLE public.todos FROM anon;
|
||||
GRANT ALL ON TABLE public.todos TO anon;
|
||||
```
|
||||
|
||||
This is the diff tool being overly cautious. If you haven't changed permissions, these lines can be safely removed.
|
||||
Deploys through the [GitHub integration](/docs/guides/deployment/branching/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 ...` may appear. Keep these if the extension is required by your migration. Remove them if the extension is already created by a previous migration or is part of the default Supabase setup.
|
||||
`CREATE EXTENSION IF NOT EXISTS ...` or `DROP EXTENSION ...` might appear when your local and remote extension sets differ. Keep the statement if it reflects a change you want. Remove it if the extension is already handled by a previous migration or you don't want to change it. Decide deliberately, because a `DROP EXTENSION` applies silently on `db reset`.
|
||||
|
||||
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` reports schema objects it doesn't track (such as casts, operators, and text search configurations) as warnings instead of silently dropping them. Add those objects through hand-written migrations. To turn these warnings into hard failures (useful in CI), pass `--strict-coverage`.
|
||||
|
||||
### Grants and revoke patterns
|
||||
|
||||
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.
|
||||
|
||||
### Known limitations of `db diff`
|
||||
|
||||
The diff is generated by `pg-delta`, the default schema diff engine. (The older [`migra`](https://github.com/djrobstep/migra) engine is still available: set `enabled = false` under `[experimental.pgdelta]` in `config.toml`, or pass `--use-migra`.) No diff engine captures everything. Most notably, DML (INSERT, UPDATE, DELETE) is not tracked, so data changes must be added to the migration manually, and some entities like RLS policy renames and certain view properties don't diff cleanly. See the [full list of caveats](/docs/guides/local-development/declarative-database-schemas#known-caveats) in the declarative schemas guide.
|
||||
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](/docs/guides/local-development/declarative-database-schemas#known-caveats) in the declarative schemas guide.
|
||||
|
||||
Treat `db diff` output as a draft, not a final migration. When in doubt, review the generated SQL and adjust it manually.
|
||||
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](/docs/guides/local-development/diff-engines) for how engine selection works and what differs between the two.
|
||||
|
||||
Treat generated output as a draft, not a final migration. When in doubt, review the generated SQL and adjust it manually.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -468,6 +489,22 @@ The remote database already has those migrations in its history. Run `supabase m
|
||||
|
||||
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` prints "No schema changes found" and exits non-zero**
|
||||
|
||||
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` warns that `schema_paths` is ignored**
|
||||
|
||||
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.
|
||||
|
||||
**The first pull after enabling `pg-delta` is unexpectedly large**
|
||||
|
||||
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`](/docs/guides/local-development/diff-engines#switch-an-existing-project-to-pg-delta) for the full procedure.
|
||||
|
||||
**A diff looks wrong or comes back empty unexpectedly**
|
||||
|
||||
Set `PGDELTA_DEBUG=1` and rerun the command. The CLI writes a debug bundle with the extracted snapshots, plan, and diagnostics. Plan bundles land under `supabase/.temp/pgdelta/v2/debug/<id>/`, and bundles from failed runs land under `supabase/.temp/pgdelta/debug/<id>/`. The bundle shows what the engine saw. Attach it when filing a CLI bug report.
|
||||
|
||||
**Docker issues on `supabase start`**
|
||||
|
||||
Ensure Docker is running and has at least 7 GB of RAM allocated. If containers fail health checks, try:
|
||||
|
||||
@@ -289,7 +289,13 @@ SUPABASE_AUTH_GITHUB_SECRET="redacted"
|
||||
|
||||
For these changes to take effect, you need to run `supabase stop` and `supabase start` again.
|
||||
|
||||
If you have additional triggers or RLS policies defined on your `auth` schema, you can pull them as a migration file locally.
|
||||
If you have additional triggers or RLS policies defined on your `auth` schema, how you pull them locally depends on your project's diff engine.
|
||||
|
||||
<$Partial path="diff_engine_check.mdx" />
|
||||
|
||||
On `pg-delta`, a plain `supabase db pull` captures your customizations automatically. Triggers on managed tables (such as a trigger on `auth.users` calling a function in `public`) and RLS policies on `auth` tables are included in the diff.
|
||||
|
||||
On the legacy `migra` engine, the initial pull's `pg_dump` skips the `auth` schema, but the diff pass that follows appends your triggers and RLS policies there to the same migration. Older CLI versions excluded the `auth` schema entirely and printed a message saying so. If you see that message, capture existing customizations once with an explicit pull:
|
||||
|
||||
```bash
|
||||
supabase db pull --schema auth
|
||||
@@ -297,7 +303,7 @@ supabase db pull --schema auth
|
||||
|
||||
### Sync storage buckets
|
||||
|
||||
Your RLS policies on storage buckets can be pulled locally by specifying `storage` schema. For example,
|
||||
On the `pg-delta` engine, your RLS policies on `storage.objects` and `storage.buckets` are also captured automatically by a plain `supabase db pull`. On the legacy `migra` engine, the diff pass that follows the initial `pg_dump` appends them to the same migration. If an older CLI prints a message that the `storage` schema was excluded, capture existing policies once with an explicit pull:
|
||||
|
||||
```bash
|
||||
supabase db pull --schema storage
|
||||
|
||||
@@ -11,7 +11,15 @@ Declarative schemas provide a developer-friendly way to maintain [schema migrati
|
||||
|
||||
[Migrations](/docs/guides/deployment/database-migrations) are traditionally managed imperatively (you provide the instructions on how exactly to change the database). This can lead to related information being scattered over multiple migration files. With declarative schemas, you instead declare the state you want your database to be in, and the instructions are generated for you.
|
||||
|
||||
Because the schema files are the source of truth, make every change by editing them - not through Studio or the SQL editor. `supabase db diff` compares your schema files, not the live database, so changes made directly to the database are not picked up.
|
||||
Because the schema files are the source of truth, make every change by editing them, not through Studio or the SQL editor. Migrations are generated from your schema files with `supabase db schema declarative sync`, which compares the files against your migration history, not the live database. Changes made directly to the database are not picked up.
|
||||
|
||||
<Admonition type="note" title="Check your diff engine first">
|
||||
|
||||
<$Partial path="diff_engine_check.mdx" />
|
||||
|
||||
This guide describes the workflow on `pg-delta`. The `db schema declarative` commands require it and won't run on the legacy engine. For a single run of `sync` or `generate` without changing `config.toml`, pass the `--experimental` flag. `db pull --declarative` runs regardless of the `[experimental.pgdelta]` setting, but only use it on `pg-delta`. On the legacy engine it leaves `db diff` unable to run. If your project is still on `migra`, follow [Declarative schemas on the legacy `migra` engine](#declarative-schemas-on-the-legacy-migra-engine) instead.
|
||||
|
||||
</Admonition>
|
||||
|
||||
## Schema migrations
|
||||
|
||||
@@ -44,13 +52,13 @@ create table "employees" (
|
||||
|
||||
<StepHikeCompact.Step step={2}>
|
||||
<StepHikeCompact.Details title="Generate a migration file">
|
||||
Generate a migration file by diffing against your declared schema.
|
||||
Generate a migration file by diffing against your declared schema. This walkthrough passes `--no-apply` so the command only writes the file and the next step applies it. Without that flag, the command offers to apply the migration to your local database. Both `--apply` and the global `--yes` flag apply it without prompting, and a non-interactive run writes the file and silently skips the apply step.
|
||||
</StepHikeCompact.Details>
|
||||
|
||||
<StepHikeCompact.Code>
|
||||
|
||||
```bash name=Terminal
|
||||
supabase db diff -f create_employees_table
|
||||
supabase db schema declarative sync -f create_employees_table --no-apply
|
||||
```
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
@@ -81,7 +89,9 @@ supabase migration up
|
||||
|
||||
<Admonition type="caution" label="Edit the schema files, not the database">
|
||||
|
||||
With declarative schemas, the files in `supabase/schemas/` are the source of truth. `supabase db diff` compares **those files** against your migrations - it does **not** read the live database. Changes you make directly (Studio, the SQL editor, `psql`) are invisible to the diff: it reports "No schema changes found" and the change is silently dropped. Always edit the schema files, then run `db diff`.
|
||||
With declarative schemas, the files in `supabase/schemas/` are the source of truth. `supabase db schema declarative sync` compares those files against your migrations. It does not read the live database. Changes you make directly (Studio, the SQL editor, `psql`) are invisible to the diff, which reports "No schema changes found" and silently drops the change. Always edit the schema files, then run `sync`.
|
||||
|
||||
Don't use `supabase db diff` here, because it diffs a live database against your migrations and never uses `supabase/schemas/` as its baseline.
|
||||
|
||||
</Admonition>
|
||||
|
||||
@@ -123,7 +133,7 @@ Some entities like views and enums expect columns to be declared in a specific o
|
||||
<StepHikeCompact.Code>
|
||||
|
||||
```bash name=Terminal
|
||||
supabase db diff -f add_age
|
||||
supabase db schema declarative sync -f add_age --no-apply
|
||||
```
|
||||
|
||||
</StepHikeCompact.Code>
|
||||
@@ -239,7 +249,9 @@ AS $$
|
||||
$$;
|
||||
```
|
||||
|
||||
Your schema files are run in lexicographic order by default. The order is important when you have foreign keys between multiple tables as the parent table must be created first. For example, your `supabase` directory may end up with the following structure.
|
||||
You don't need to order your schema files manually. When generating a migration, the engine analyzes the dependencies between your statements, such as foreign keys, views over tables, and functions used by triggers, and orders them automatically. File names and directory layout are for readability only. If your statements contain a dependency cycle, the command fails with a diagnostic instead of producing a broken migration.
|
||||
|
||||
This means you can organize `supabase/schemas/` however you like. For example, one file per table:
|
||||
|
||||
```bash
|
||||
.
|
||||
@@ -253,25 +265,25 @@ Your schema files are run in lexicographic order by default. The order is import
|
||||
└── 20241006112233_add_managers_table.sql
|
||||
```
|
||||
|
||||
For small projects with only a few tables, the default schema order may be sufficient. However, as your project grows, you might need more control over the order in which schemas are applied. To specify a custom order for applying the schemas, you can declare them explicitly in `config.toml`. Any glob patterns will evaluated, deduplicated, and sorted in lexicographic order. For example, the following pattern ensures `employees.sql` is always executed first.
|
||||
Or the per-schema layout that `supabase db schema declarative generate` produces, with one directory per database schema (such as `supabase/schemas/public/tables/employees.sql`) and cluster-level objects like roles under a reserved `_cluster/` directory. You can also create a reserved `_custom/` directory for hand-authored SQL covering objects the engine doesn't track. `generate` doesn't create it, and once it exists the export never writes to it or prunes it. See [Known caveats](#known-caveats).
|
||||
|
||||
```toml name=supabase/config.toml
|
||||
[db.migrations]
|
||||
schema_paths = [
|
||||
"./schemas/employees.sql",
|
||||
"./schemas/*.sql",
|
||||
]
|
||||
```
|
||||
<Admonition type="note">
|
||||
|
||||
Under the `pg-delta` engine, the `[db.migrations].schema_paths` setting from earlier CLI versions no longer controls declarative file ordering, because ordering is automatic. The CLI warns when the setting lists any paths. On the legacy `migra` engine, `schema_paths` still controls the order in which declarative files are applied. See [Ordering schema files](#ordering-schema-files-on-the-legacy-engine).
|
||||
|
||||
</Admonition>
|
||||
|
||||
### Pulling in your production schema
|
||||
|
||||
To set up declarative schemas on a existing project, you can pull in your production schema by running:
|
||||
To set up declarative schemas on an existing project, export your production schema into declarative files:
|
||||
|
||||
```bash name=Terminal
|
||||
supabase db dump > supabase/schemas/prod.sql
|
||||
supabase db schema declarative generate --linked
|
||||
```
|
||||
|
||||
From there, you can start breaking down your schema into smaller files and generate migrations. You can do this all at once, or incrementally as you make changes to your schema.
|
||||
This writes per-object SQL files under `supabase/schemas/` (or the directory set by `experimental.pgdelta.declarative_schema_path`), organized by database schema. In scripts, pass the target explicitly (`--local`, `--linked`, or `--db-url`) and add `--overwrite` to replace an existing tree without prompting. To later refresh the declarative tree from the remote database (for example, after a change was deployed outside your local workflow), run `supabase db pull --declarative`. It replaces the schema files without creating a migration or touching migration history.
|
||||
|
||||
`generate` writes schema files only. Because `sync` diffs your schema files against your migration history, that history must describe the same database before your first `sync`. If your project has no migrations yet, run `supabase db pull` first to create a baseline migration. Without a baseline, the first `sync` regenerates the entire schema as one migration. That migration can apply cleanly to an empty local database and still fail on `db push`, because the remote database already has those objects.
|
||||
|
||||
### Rolling back a schema change
|
||||
|
||||
@@ -293,31 +305,94 @@ SQL statements generated in a down migration are usually destructive. You must r
|
||||
|
||||
## Known caveats
|
||||
|
||||
Schema diffs are generated by `pg-delta`, the default diff engine, which tracks most database changes. However, there are edge cases where schema diff can fail. The known cases below were documented against the legacy [`migra`](https://github.com/djrobstep/migra) engine (still available via `enabled = false` under `[experimental.pgdelta]` in `config.toml`, or `--use-migra`); some, such as duplicated grants from default privileges, also apply to `pg-delta`. Review every generated migration regardless of engine.
|
||||
|
||||
If you need to use any of the entities below, remember to add them through [versioned migrations](/docs/guides/deployment/database-migrations) instead.
|
||||
Schema diffs are generated by `pg-delta`, which models most database entities, including tables, views, materialized views, functions, triggers, RLS policies, grants, comments, domains, partitions, and publications. There are still cases it cannot capture. Review every generated migration before committing.
|
||||
|
||||
### Data manipulation language
|
||||
|
||||
- DML statements such as `insert`, `update`, `delete`, etc., are not captured by schema diff
|
||||
DML statements such as `insert`, `update`, and `delete` are never captured by a schema diff. This includes storage buckets, which are rows in the `storage.buckets` table rather than schema objects. A DML statement inside a declarative schema file is an error. Keep data changes in [seed files](/docs/guides/local-development/seeding-your-database) or hand-written [versioned migrations](/docs/guides/deployment/database-migrations).
|
||||
|
||||
### View ownership
|
||||
### Default privileges on new objects
|
||||
|
||||
- [view owner and grants](https://github.com/djrobstep/migra/issues/160#issuecomment-1702983833)
|
||||
- [security invoker on views](https://github.com/djrobstep/migra/issues/234)
|
||||
- [materialized views](https://github.com/djrobstep/migra/issues/194)
|
||||
- doesn’t recreate views when altering column type
|
||||
Both engines treat permissions as part of the schema state. When you create a new object, generated migrations can include `GRANT`/`REVOKE` statements you didn't write, reflecting default privileges. If you haven't customized permissions, these lines are safe to remove.
|
||||
|
||||
### RLS policies
|
||||
### Object kinds that aren't tracked
|
||||
|
||||
- [alter policy statements](https://github.com/djrobstep/schemainspect/blob/master/schemainspect/pg/obj.py#L228)
|
||||
- [column privileges](https://github.com/djrobstep/schemainspect/pull/67)
|
||||
Some object kinds are not tracked by the engine: casts, operators, operator classes and families, text search configurations, dictionaries, parsers, and templates, statistics objects, languages, transforms, and parameter ACLs. They are never silently dropped. The engine reports them as warnings, and you can pass `--strict-coverage` to turn those warnings into hard failures (useful in CI).
|
||||
|
||||
### Other entities
|
||||
To use these objects with declarative schemas, create the reserved `supabase/schemas/_custom/` directory if it doesn't exist and put their SQL there so dependent objects still resolve. `generate` never creates, overwrites, or prunes that directory. Deliver the change itself through a versioned migration, and make sure that migration sorts before the generated migration that depends on the object. Otherwise `db reset` and every later `sync` fail. Parameter ACLs are the exception because they live in a catalog shared by every database in the cluster. Keep them out of `_custom/` and manage them through versioned migrations only.
|
||||
|
||||
- schema privileges are not tracked because each schema is diffed separately
|
||||
- [comments are not tracked](https://github.com/djrobstep/migra/issues/69)
|
||||
- [partitions are not tracked](https://github.com/djrobstep/migra/issues/186)
|
||||
- [`alter publication ... add table ...`](https://github.com/supabase/cli/issues/883)
|
||||
- [create domain statements are ignored](https://github.com/supabase/cli/issues/2137)
|
||||
- [grant statements are duplicated from default privileges](https://github.com/supabase/cli/issues/1864)
|
||||
### Supabase-managed schemas
|
||||
|
||||
<$Partial path="managed_schemas_diff_capture.mdx" />
|
||||
|
||||
Manage those objects through versioned migrations.
|
||||
|
||||
### Extension-managed objects
|
||||
|
||||
Objects that belong to an extension are recognized as the extension's, not yours. Anything an extension owns is excluded from diffs. Objects extensions create as they run, such as partitions maintained by `pg_partman` and queue tables created by `pgmq`, are never emitted as raw `create table` or `drop table` statements. The diff expresses changes to them through the extension's own API instead, such as `select pgmq.drop_queue('q');` or a `delete from partman.part_config` row, and the CLI flags those statements as destructive. Create and change these objects through the extension's own functions, and review any generated API calls before committing.
|
||||
|
||||
### Adopting an existing schema tree
|
||||
|
||||
Two checks gate `sync` on a schema tree the CLI didn't generate:
|
||||
|
||||
- If your migrations call `pg_net` (for example, database webhooks), add `[experimental.webhooks]` with `enabled = true` to `config.toml` first. The section isn't part of the default `init` template.
|
||||
- Declare the extensions your schema files depend on. The check trips for `pg_net` and for extensions your own migrations create. When it does, interactive `sync` offers to add the missing declaration and re-plan, or to stage a fresh export into a sibling `-next` directory and print the commands to adopt it. A non-interactive run only prints those commands. Extensions the local stack already ships, such as `pgcrypto` and `uuid-ossp`, don't trip the check even when undeclared, so declare them yourself.
|
||||
|
||||
## Declarative schemas on the legacy `migra` engine [#declarative-schemas-on-the-legacy-migra-engine]
|
||||
|
||||
Projects that haven't enabled `pg-delta` can still use declarative schemas. The workflow has the same shape, but the commands differ, and the `db schema declarative` commands aren't available. See [Diff engines](/docs/guides/local-development/diff-engines) for how to check which engine you're on and how the engines compare.
|
||||
|
||||
<Admonition type="caution">
|
||||
|
||||
On the legacy engine, don't run `supabase db pull --declarative`. The command runs regardless of the `[experimental.pgdelta]` setting, but the tree it writes is only readable by the `db schema declarative` commands. `db diff` on the legacy engine tries to load that tree as its baseline, in lexicographic order, and fails on the first file. If you've already run it, delete the generated tree under `supabase/schemas/` or [switch to `pg-delta`](#switching-to-pg-delta).
|
||||
|
||||
</Admonition>
|
||||
|
||||
### Generating migrations on the legacy engine
|
||||
|
||||
On the legacy engine, `supabase db diff` reads your declarative files. When `supabase/schemas/` contains files, it compares them against your migrations instead of reading the live database. Generate migrations with the local stack stopped.
|
||||
|
||||
1. Edit the files in `supabase/schemas/`.
|
||||
2. Stop the local stack and generate a migration:
|
||||
|
||||
```bash
|
||||
supabase stop
|
||||
supabase db diff -f add_age
|
||||
```
|
||||
|
||||
3. Start the stack and apply the migration:
|
||||
|
||||
```bash
|
||||
supabase start
|
||||
supabase migration up
|
||||
```
|
||||
|
||||
As on `pg-delta`, changes made directly through Studio, the SQL editor, or `psql` are not picked up. Always edit the schema files, then diff.
|
||||
|
||||
### Ordering schema files on the legacy engine
|
||||
|
||||
The legacy engine applies your schema files in lexicographic order. The order matters when tables reference each other, because the parent table must be created first. To control the order, list files or glob patterns under `[db.migrations].schema_paths` in `config.toml`. The CLI processes the entries in the order you list them: it expands each pattern, sorts that pattern's matches lexicographically, and skips any file an earlier entry already matched. This example always runs `employees.sql` first:
|
||||
|
||||
```toml name=supabase/config.toml
|
||||
[db.migrations]
|
||||
schema_paths = [
|
||||
"./schemas/employees.sql",
|
||||
"./schemas/*.sql",
|
||||
]
|
||||
```
|
||||
|
||||
### Starting from an existing database on the legacy engine
|
||||
|
||||
`supabase db schema declarative generate` isn't available on the legacy engine. Instead, dump your production schema into a single file and split it into smaller files over time:
|
||||
|
||||
```bash
|
||||
supabase db dump > supabase/schemas/prod.sql
|
||||
```
|
||||
|
||||
### Limitations of the legacy engine [#limitations-of-the-legacy-engine]
|
||||
|
||||
In addition to the caveats above, the legacy [`migra`](https://github.com/djrobstep/migra) engine has these limitations: [view owner and grants](https://github.com/djrobstep/migra/issues/160#issuecomment-1702983833), [security invoker on views](https://github.com/djrobstep/migra/issues/234) (the setting is silently dropped from the view definition), [indexes on a materialized view aren't restored when the view is recreated](https://github.com/djrobstep/migra/issues/194), [alter policy statements](https://github.com/djrobstep/schemainspect/blob/master/schemainspect/pg/obj.py#L228), [column privileges](https://github.com/djrobstep/schemainspect/pull/67), [comments](https://github.com/djrobstep/migra/issues/69), [roles](https://github.com/djrobstep/migra/issues/240), [`alter publication ... add table`](https://github.com/supabase/cli/issues/883), and [`create domain` statements](https://github.com/supabase/cli/issues/2137). Add those entities through versioned migrations instead.
|
||||
|
||||
### Switching to `pg-delta` [#switching-to-pg-delta]
|
||||
|
||||
Follow [Switch an existing project to `pg-delta`](/docs/guides/local-development/diff-engines#switch-an-existing-project-to-pg-delta). For a declarative project, the steps that change your day-to-day work are removing `schema_paths`, replacing `db diff` with `db schema declarative sync` in scripts and CI, and dropping the `supabase stop` step.
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
id: 'diff-engines'
|
||||
title: 'Diff engines: pg-delta and migra'
|
||||
description: 'How the Supabase CLI generates migrations, which engine your project uses, and how to switch.'
|
||||
subtitle: 'How the Supabase CLI generates migrations, which engine your project uses, and how to switch.'
|
||||
---
|
||||
|
||||
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`](https://github.com/supabase/pg-toolbelt/tree/main/packages/pg-delta) is Supabase's open source engine and the default for projects created with a recent `supabase init`. Rather than parsing SQL to understand your schema, it loads each state into a real Postgres instance and reads the result from the catalog. It models entities the legacy engine missed, such as comments, domains, roles, publication membership, and the security invoker setting on views, and it supports Postgres 14 through 18. It ships under the `[experimental.pgdelta]` config namespace and remains pre-1.0.
|
||||
|
||||
[`migra`](https://github.com/djrobstep/migra) is `djrobstep`'s open source Python library for diffing Postgres schemas, and the CLI has shelled out to it since before `pg-delta` existed. It compares two live Postgres databases and generates the SQL that turns one into the other, the mechanism behind `supabase db diff`. Projects that haven't opted in to `pg-delta` continue to use it, and every command they relied on keeps working.
|
||||
|
||||
## Which engine your project uses
|
||||
|
||||
<$Partial path="diff_engine_check.mdx" />
|
||||
|
||||
Projects created with a recent `supabase init` use `pg-delta` because `init` writes this into `config.toml`:
|
||||
|
||||
```toml name=supabase/config.toml
|
||||
[experimental.pgdelta]
|
||||
enabled = true
|
||||
```
|
||||
|
||||
Existing projects without that section keep the legacy `migra` engine until they add it. See [Switch an existing project to `pg-delta`](#switch-an-existing-project-to-pg-delta).
|
||||
|
||||
To use `migra` for a single run without changing `config.toml`, the flag depends on the command:
|
||||
|
||||
| Command | Flag to fall back to `migra` |
|
||||
| --------- | ---------------------------- |
|
||||
| `db diff` | `--use-migra` |
|
||||
| `db pull` | `--diff-engine migra` |
|
||||
|
||||
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.
|
||||
|
||||
| Behavior | `pg-delta` | Legacy `migra` |
|
||||
| -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| What `db diff` compares | Always the live database against a shadow database built from your migrations. Never reads `supabase/schemas/`. | The live database against your migrations, unless `supabase/schemas/` contains declarative files. Then it compares those files against your migrations instead. |
|
||||
| Generating migrations from declarative files | `supabase db schema declarative sync` | `supabase db diff`, with the local stack stopped |
|
||||
| Exporting a database into declarative files | `supabase db schema declarative generate` | Not available. Use `supabase db dump` and split the output by hand. |
|
||||
| Ordering of declarative files | Automatic, based on dependencies between statements. `[db.migrations].schema_paths` is ignored, and the CLI warns when the setting lists any paths. | Lexicographic by default. `[db.migrations].schema_paths` overrides the order. Files in `supabase/schemas/` are used even when the setting is empty. |
|
||||
| Initial `db pull` (empty migration history) | Diffs the remote database against an empty shadow database. Your customizations in managed schemas, such as triggers on `auth.users` and RLS policies on `storage.objects`, are included. | Seeds the migration with `pg_dump`, which skips managed schemas, then appends a diff of your triggers and RLS policies in `auth` and `storage`. Older versions excluded those schemas and told you to run `supabase db pull --schema auth,storage`. |
|
||||
| Later `db pull` runs | Diffs the remote database against your migrations. | Same. Trigger and RLS policy changes in managed schemas are included. |
|
||||
| `db pull --declarative` | Replaces `supabase/schemas/` from the selected database without creating a migration. | Runs, but don't use it. The tree it writes is only readable by the `db schema declarative` commands. `db diff` on the legacy engine then tries to load that tree as its baseline and fails. |
|
||||
| Objects the engine doesn't track | Reported as warnings and never silently dropped. Pass `--strict-coverage` to turn the warnings into failures. | Silently omitted. `--strict-coverage` has no effect. |
|
||||
| Generated SQL | Uppercase keywords wrapped at 180 characters. Configurable with `[experimental.pgdelta] format_options`. | Engine default formatting. |
|
||||
| Migration files per run | Usually one. When a change crosses a transaction boundary, it may write one ordered file per unit with `_1`, `_2` suffixes. Files whose statements can't run in a transaction start with `-- pg-delta: transaction=false`. | One file. |
|
||||
| Known limitations | See [Known caveats](/docs/guides/local-development/declarative-database-schemas#known-caveats). | See [Limitations of the legacy engine](/docs/guides/local-development/declarative-database-schemas#limitations-of-the-legacy-engine). |
|
||||
|
||||
For a walkthrough of the day-to-day commands on `pg-delta`, see [Local development workflow](/docs/guides/local-development/cli-workflows). For the declarative workflow on each engine, see [Declarative database schemas](/docs/guides/local-development/declarative-database-schemas).
|
||||
|
||||
## Switch an existing project to `pg-delta` [#switch-an-existing-project-to-pg-delta]
|
||||
|
||||
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. Add the engine setting to `config.toml`:
|
||||
|
||||
```toml name=supabase/config.toml
|
||||
[experimental.pgdelta]
|
||||
enabled = true
|
||||
```
|
||||
|
||||
2. If your project uses declarative schemas, remove `[db.migrations].schema_paths`. Ordering is automatic on `pg-delta`, and the CLI warns when the setting lists any paths.
|
||||
|
||||
3. Pull once against your linked project to create a catch-up migration:
|
||||
|
||||
```bash
|
||||
supabase db pull
|
||||
```
|
||||
|
||||
If your history was built from legacy diffs, it doesn't mention objects the legacy engine didn't track, such as comments, domains, roles, and publication membership. This first pull captures them in a single catch-up migration. Your remote database already has these objects, 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, it already contains those objects, and this pull reports "No schema changes found". There is nothing to commit in that case. See [Cleaning up generated migrations](/docs/guides/local-development/cli-workflows#cleaning-up-generated-migrations).
|
||||
|
||||
4. Replace `supabase db diff` with `supabase db schema declarative sync` wherever you generate migrations from declarative files, including shell scripts, CI jobs, and AI prompt files such as [`examples/prompts/declarative-database-schema.md`](https://github.com/supabase/supabase/blob/master/examples/prompts/declarative-database-schema.md). You no longer need to run `supabase stop` before generating. If the CLI didn't generate your schema tree, see [Adopting an existing schema tree](/docs/guides/local-development/declarative-database-schemas#adopting-an-existing-schema-tree) for two checks that run on the first `sync`.
|
||||
|
||||
5. Verify the full migration chain locally:
|
||||
|
||||
```bash
|
||||
supabase db reset
|
||||
```
|
||||
|
||||
6. Optionally, add `supabase db diff --strict-coverage` to CI so untracked objects fail the job instead of producing warnings. See [Managing environments](/docs/guides/deployment/managing-environments).
|
||||
|
||||
If you deploy through the [GitHub integration](/docs/guides/deployment/branching/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.
|
||||
|
||||
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.
|
||||
@@ -230,13 +230,28 @@ psql \
|
||||
|
||||
#### Schema changes to `auth` and `storage`
|
||||
|
||||
If you have modified the `auth` and `storage` schemas in your old project, such as adding triggers or Row Level Security(RLS) policies, you have to restore them separately. The Supabase CLI can help you diff the changes to these schemas using the following commands.
|
||||
If you have modified the `auth` and `storage` schemas in your old project, such as adding triggers or Row Level Security (RLS) policies, you have to restore them separately. The Supabase CLI can help you diff the old project against your local migrations. The command depends on your project's diff engine.
|
||||
|
||||
<$Partial path="diff_engine_check.mdx" />
|
||||
|
||||
On `pg-delta`, a plain diff includes your customizations in the managed schemas:
|
||||
|
||||
```bash
|
||||
supabase link --project-ref "$OLD_PROJECT_REF"
|
||||
supabase db diff --linked > changes.sql
|
||||
```
|
||||
|
||||
<$Partial path="managed_schemas_diff_capture.mdx" />
|
||||
|
||||
On the legacy `migra` engine, name the schemas explicitly:
|
||||
|
||||
```bash
|
||||
supabase link --project-ref "$OLD_PROJECT_REF"
|
||||
supabase db diff --linked --schema auth,storage > changes.sql
|
||||
```
|
||||
|
||||
Recreate those objects on the new project from your own migration files or through the Dashboard.
|
||||
|
||||
### Troubleshooting notes
|
||||
|
||||
#### Disabling triggers during restore:
|
||||
|
||||
@@ -2961,10 +2961,20 @@ commands:
|
||||
name: --name <string>
|
||||
description: Name for the generated migration file.
|
||||
default_value: ''
|
||||
- id: no-apply
|
||||
name: --no-apply
|
||||
description: |
|
||||
Generate the migration file without prompting or applying it to the local database.
|
||||
default_value: 'false'
|
||||
- id: schema
|
||||
name: -s, --schema <strings>
|
||||
description: Comma separated list of schema to include.
|
||||
default_value: '[]'
|
||||
- id: strict-coverage
|
||||
name: --strict-coverage
|
||||
description: |
|
||||
Fail when bundled pg-delta finds schema objects it cannot manage instead of leaving them unmanaged.
|
||||
default_value: 'false'
|
||||
- id: experimental
|
||||
name: --experimental
|
||||
description: enable experimental features
|
||||
@@ -3002,6 +3012,11 @@ commands:
|
||||
name: --local
|
||||
description: Generates declarative schema from the local database.
|
||||
default_value: 'false'
|
||||
- id: output-dir
|
||||
name: --output-dir <string>
|
||||
description: |
|
||||
Write declarative schema files to this directory instead of the configured declarative schema directory.
|
||||
default_value: ''
|
||||
- id: overwrite
|
||||
name: --overwrite
|
||||
description: Overwrite declarative schema files without confirmation.
|
||||
@@ -3019,6 +3034,11 @@ commands:
|
||||
name: -s, --schema <strings>
|
||||
description: Comma separated list of schema to include.
|
||||
default_value: '[]'
|
||||
- id: strict-coverage
|
||||
name: --strict-coverage
|
||||
description: |
|
||||
Fail when bundled pg-delta finds schema objects it cannot manage instead of leaving them unmanaged.
|
||||
default_value: 'false'
|
||||
- id: experimental
|
||||
name: --experimental
|
||||
description: enable experimental features
|
||||
@@ -3212,9 +3232,11 @@ commands:
|
||||
|
||||
Optionally, a new row can be inserted into the migration history table to reflect the current state of the remote database.
|
||||
|
||||
If no entries exist in the migration history table, `pg_dump` will be used to capture all contents of the remote schemas you have created. Otherwise, this command will only diff schema changes against the remote database, similar to running `db diff --linked`.
|
||||
If no entries exist in the migration history table, the behavior depends on the diff engine. Under `pg-delta`, the remote database is diffed against an empty shadow database. Under the legacy `migra` engine, the CLI uses `pg_dump` to capture all contents of the remote schemas you have created. Otherwise, this command only diffs schema changes against the remote database, similar to running `db diff --linked`.
|
||||
|
||||
Pass `--diff-engine pg-delta` to keep the migration-file `db pull` workflow while using pg-delta for the shadow diff step. Pass `--use-pg-delta` to switch to the declarative pg-delta export workflow instead.
|
||||
When `[experimental.pgdelta] enabled = true`, the migration-file `db pull` workflow uses pg-delta for the shadow diff step; pass `--diff-engine migra` to fall back for a single run. Projects without that setting use migra; pass `--diff-engine pg-delta` to use pg-delta for a single run. Pass `--declarative` to replace the declarative schema tree (`supabase/schemas` by default, configurable with `experimental.pgdelta.declarative_schema_path`) from the selected database instead of creating a migration.
|
||||
|
||||
Under the pg-delta engine, your own customizations in Supabase-managed schemas are captured automatically, such as triggers on managed tables like `auth.users` and RLS policies on `storage.objects` and `storage.buckets`. Under the legacy migra engine, the initial pull's `pg_dump` skips managed schemas, but the diff pass that follows appends your trigger and RLS policy changes there to the same migration. If an older CLI reports that `auth` and `storage` were excluded, capture existing customizations there with `--schema auth,storage`.
|
||||
examples:
|
||||
- id: basic-usage
|
||||
name: Basic usage
|
||||
@@ -3225,28 +3247,29 @@ commands:
|
||||
Update remote migration history table? [Y/n]
|
||||
Repaired migration history: [20240414044403] => applied
|
||||
Finished supabase db pull.
|
||||
The auth and storage schemas are excluded. Run supabase db pull --schema auth,storage again to diff them.
|
||||
- id: local-studio
|
||||
name: Local studio
|
||||
code: supabase db pull --local
|
||||
response: |
|
||||
Connecting to local database...
|
||||
Setting up initial schema....
|
||||
Creating custom roles supabase/roles.sql...
|
||||
Creating shadow database...
|
||||
Seeding globals from roles.sql...
|
||||
Applying migration 20240414044403_remote_schema.sql...
|
||||
Diffing schemas...
|
||||
No schema changes found
|
||||
The auth and storage schemas are excluded. Run supabase db pull --schema auth,storage again to diff them.
|
||||
The remote database is already in sync with your local migrations — nothing to pull.
|
||||
exit status 1
|
||||
- id: custom-schemas
|
||||
name: Custom schemas
|
||||
code: supabase db pull --schema auth,storage
|
||||
code: supabase db pull --schema public,extensions
|
||||
response: |
|
||||
Connecting to remote database...
|
||||
Setting up initial schema....
|
||||
Creating custom roles supabase/roles.sql...
|
||||
Creating shadow database...
|
||||
Seeding globals from roles.sql...
|
||||
Applying migration 20240414044403_remote_schema.sql...
|
||||
Diffing schemas: public,extensions
|
||||
No schema changes found
|
||||
Try rerunning the command with --debug to troubleshoot the error.
|
||||
The remote database is already in sync with your local migrations — nothing to pull.
|
||||
exit status 1
|
||||
tags: []
|
||||
links: []
|
||||
@@ -3258,6 +3281,11 @@ commands:
|
||||
description: |
|
||||
Pulls from the database specified by the connection string (must be percent-encoded).
|
||||
default_value: ''
|
||||
- id: declarative
|
||||
name: --declarative
|
||||
description: |
|
||||
Replace the declarative schema tree from the selected database instead of creating a migration. Migration history is not updated. Only use this on projects with `[experimental.pgdelta] enabled = true`. On the legacy migra engine, `db diff` tries to load the generated tree as its baseline and fails.
|
||||
default_value: 'false'
|
||||
- id: diff-engine
|
||||
name: --diff-engine <[ migra | pg-delta ]>
|
||||
description: Diff engine to use for migration-style db pull.
|
||||
@@ -3285,9 +3313,15 @@ commands:
|
||||
name: -s, --schema <strings>
|
||||
description: Comma separated list of schema to include.
|
||||
default_value: '[]'
|
||||
- id: strict-coverage
|
||||
name: --strict-coverage
|
||||
description: |
|
||||
Fail when bundled pg-delta finds schema objects it cannot manage instead of leaving them unmanaged.
|
||||
default_value: 'false'
|
||||
- id: use-pg-delta
|
||||
name: --use-pg-delta
|
||||
description: Use pg-delta to pull declarative schema.
|
||||
description: |
|
||||
Use pg-delta to pull declarative schema. Deprecated: use `--declarative` instead.
|
||||
default_value: 'false'
|
||||
- id: supabase-db-lint
|
||||
title: supabase db lint
|
||||
@@ -3484,11 +3518,13 @@ commands:
|
||||
|
||||
Requires the local development stack to be running when diffing against the local database. To diff against a remote or self-hosted database, specify the `--linked` or `--db-url` flag respectively.
|
||||
|
||||
Runs [djrobstep/migra](https://github.com/djrobstep/migra) in a container to compare schema differences between the target database and a shadow database. The shadow database is created by applying migrations in local `supabase/migrations` directory in a separate container. Output is written to stdout by default. For convenience, you can also save the schema diff as a new migration file by passing in `-f` flag.
|
||||
Compares schema differences between the target database and a shadow database. Projects with `[experimental.pgdelta] enabled = true` use the bundled pg-delta engine; other projects run the legacy [djrobstep/migra](https://github.com/djrobstep/migra) engine in a container. The shadow database is created by applying migrations in local `supabase/migrations` directory in a separate container. Output is written to stdout by default. For convenience, you can also save the schema diff as a new migration file by passing in `-f` flag.
|
||||
|
||||
By default, all schemas in the target database are diffed. Use the `--schema public,extensions` flag to restrict diffing to a subset of schemas.
|
||||
|
||||
While the diff command is able to capture most schema changes, there are cases where it is known to fail. Currently, this could happen if you schema contains:
|
||||
Projects created by a recent `supabase init` default to pg-delta (`[experimental.pgdelta] enabled = true` in `config.toml`). Existing projects keep using migra unless they opt in. To fall back to migra for a single run on a pg-delta project, pass `--use-migra`.
|
||||
|
||||
Under the legacy migra engine, the diff is known to miss some changes. This could happen if your schema contains:
|
||||
|
||||
- Changes to publication
|
||||
- Changes to storage buckets
|
||||
@@ -3560,6 +3596,11 @@ commands:
|
||||
name: -s, --schema <strings>
|
||||
description: Comma separated list of schema to include.
|
||||
default_value: '[]'
|
||||
- id: strict-coverage
|
||||
name: --strict-coverage
|
||||
description: |
|
||||
Fail when bundled pg-delta finds schema objects it cannot manage instead of leaving them unmanaged.
|
||||
default_value: 'false'
|
||||
- id: to
|
||||
name: --to <string>
|
||||
description: Diff to local, linked, migrations, or a Postgres URL.
|
||||
|
||||
@@ -449,6 +449,18 @@ parameters:
|
||||
- name: 'PgBouncer Configuration'
|
||||
link: https://www.pgbouncer.org/config.html#max_client_conn
|
||||
|
||||
- id: 'db.migrations.schema_paths'
|
||||
title: 'db.migrations.schema_paths'
|
||||
tags: ['database']
|
||||
required: false
|
||||
default: '[]'
|
||||
description: |
|
||||
An ordered list of schema files, directories, or glob patterns describing your database, relative to the `supabase` directory. For example: `["./schemas/*.sql"]`.
|
||||
Only the legacy `migra` diff engine uses this setting, where it controls the order in which declarative schema files are applied. The `pg-delta` diff engine (see `experimental.pgdelta.enabled`) ignores it and orders declarative files automatically based on the dependencies between statements.
|
||||
links:
|
||||
- name: 'Declarative database schemas'
|
||||
link: 'https://supabase.com/docs/guides/local-development/declarative-database-schemas'
|
||||
|
||||
- id: 'db.seed.enabled'
|
||||
title: 'db.seed.enabled'
|
||||
tags: ['database']
|
||||
@@ -1799,6 +1811,42 @@ parameters:
|
||||
Note: This is an experimental feature and may change in future releases.
|
||||
links: []
|
||||
|
||||
- id: 'experimental.pgdelta.enabled'
|
||||
title: 'experimental.pgdelta.enabled'
|
||||
tags: ['experimental']
|
||||
required: false
|
||||
default: 'false'
|
||||
description: |
|
||||
Enables the `pg-delta` diff engine for `db diff`, `db pull`, and the `db schema declarative` commands.
|
||||
Projects created with a recent `supabase init` have this set to `true` in the generated `config.toml`. Existing projects keep the legacy `migra` engine until they opt in by adding this setting. Set to `false` to fall back to `migra`.
|
||||
Note: This is an experimental feature and may change in future releases.
|
||||
links:
|
||||
- name: 'Declarative database schemas'
|
||||
link: 'https://supabase.com/docs/guides/local-development/declarative-database-schemas'
|
||||
|
||||
- id: 'experimental.pgdelta.declarative_schema_path'
|
||||
title: 'experimental.pgdelta.declarative_schema_path'
|
||||
tags: ['experimental']
|
||||
required: false
|
||||
default: './schemas'
|
||||
description: |
|
||||
The directory where the `pg-delta` engine reads and writes declarative schema files. Relative paths resolve from the `supabase` directory.
|
||||
Note: This is an experimental feature and may change in future releases.
|
||||
links:
|
||||
- name: 'Declarative database schemas'
|
||||
link: 'https://supabase.com/docs/guides/local-development/declarative-database-schemas'
|
||||
|
||||
- id: 'experimental.pgdelta.format_options'
|
||||
title: 'experimental.pgdelta.format_options'
|
||||
tags: ['experimental']
|
||||
required: false
|
||||
description: |
|
||||
A JSON string of formatting options applied to SQL generated by the `pg-delta` engine. When unset, generated SQL uses uppercase keywords wrapped at a maximum line width of 180 characters.
|
||||
Supported keys: `keywordCase` (`"upper"`, `"lower"`, or `"preserve"`), `commaStyle` (`"trailing"` or `"leading"`), `indent` (number), `maxWidth` (number), and the booleans `alignColumns`, `alignKeyValues`, `preserveRoutineBodies`, `preserveViewBodies`, and `preserveRuleBodies`. Omitted keys keep their defaults.
|
||||
For example: `format_options = "{\"keywordCase\":\"lower\",\"maxWidth\":80}"`. Set `format_options = "null"` to emit raw statements with no formatting applied.
|
||||
Note: This is an experimental feature and may change in future releases.
|
||||
links: []
|
||||
|
||||
- id: 'remotes.branch_name.project_id'
|
||||
title: 'remotes.<branch_name>.project_id'
|
||||
tags: ['branching']
|
||||
|
||||
@@ -160,6 +160,30 @@
|
||||
"title": "Start only the local database",
|
||||
"slug": "supabase-db-start",
|
||||
"type": "cli-command"
|
||||
},
|
||||
{
|
||||
"id": "supabase-db-schema",
|
||||
"title": "Manage database schema",
|
||||
"slug": "supabase-db-schema",
|
||||
"type": "cli-command"
|
||||
},
|
||||
{
|
||||
"id": "supabase-db-schema-declarative",
|
||||
"title": "Manage declarative database schemas",
|
||||
"slug": "supabase-db-schema-declarative",
|
||||
"type": "cli-command"
|
||||
},
|
||||
{
|
||||
"id": "supabase-db-schema-declarative-sync",
|
||||
"title": "Generate a new migration from declarative schema",
|
||||
"slug": "supabase-db-schema-declarative-sync",
|
||||
"type": "cli-command"
|
||||
},
|
||||
{
|
||||
"id": "supabase-db-schema-declarative-generate",
|
||||
"title": "Generate declarative schema from a database",
|
||||
"slug": "supabase-db-schema-declarative-generate",
|
||||
"type": "cli-command"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -10,68 +10,81 @@ Mandatory Instructions for Supabase Declarative Schema Management
|
||||
|
||||
## 1. **Exclusive Use of Declarative Schema**
|
||||
|
||||
-**All database schema modifications must be defined within `.sql` files located in the `supabase/schemas/` directory. -**Do not\*\* create or modify files directly in the `supabase/migrations/` directory unless the modification is about the known caveats below. Migration files are to be generated automatically through the CLI.
|
||||
- **All database schema modifications must be defined within `.sql` files located in the `supabase/schemas/` directory**
|
||||
- **Do not** create or modify files directly in the `supabase/migrations/` directory unless the change falls under the known caveats below. Generate migration files through the CLI instead
|
||||
- **Do not** modify the database directly through Studio, the SQL editor, or `psql`. The schema files are the source of truth. Direct database changes are invisible to the diff and are silently dropped
|
||||
|
||||
## 2. **Schema Declaration**
|
||||
## 2. **Prerequisites**
|
||||
|
||||
-For each database entity (e.g., tables, views, functions), create or update a corresponding `.sql` file in the `supabase/schemas/` directory
|
||||
-Ensure that each `.sql` file accurately represents the desired final state of the entity
|
||||
|
||||
## 3. **Migration Generation**
|
||||
|
||||
- Before generating migrations, **stop the local Supabase development environment**
|
||||
```bash
|
||||
supabase stop
|
||||
- The declarative workflow requires the `pg-delta` diff engine. Ensure `supabase/config.toml` contains:
|
||||
```toml
|
||||
[experimental.pgdelta]
|
||||
enabled = true
|
||||
```
|
||||
- Generate migration files by diffing the declared schema against the current database state
|
||||
- Projects created with a recent `supabase init` have this enabled by default. On older projects, add the section above before generating migrations. Alternatively, pass the `--experimental` flag for a single command run
|
||||
|
||||
## 3. **Schema Declaration**
|
||||
|
||||
- For each database entity (e.g., tables, views, functions), create or update a corresponding `.sql` file in the `supabase/schemas/` directory
|
||||
- Ensure that each `.sql` file accurately represents the desired final state of the entity
|
||||
|
||||
## 4. **Migration Generation**
|
||||
|
||||
- After editing files in `supabase/schemas/`, generate and apply a migration in one step:
|
||||
```bash
|
||||
supabase db diff -f <migration_name>
|
||||
supabase db schema declarative sync -f <migration_name> --apply
|
||||
```
|
||||
Replace `<migration_name>` with a descriptive name for the migration
|
||||
- `--apply` (or the global `--yes`) applies the generated migration to the local database without prompting. Without either flag, the command prompts in a terminal and only writes the file when run non-interactively. Pass `--no-apply` to only generate the file
|
||||
- **Do not** run `supabase stop` first. The local stack can stay running because `sync` compares your schema files against your migration history, not the live database
|
||||
- **Do not** use `supabase db diff` to generate migrations from schema files. It diffs a live database against your migrations and never uses `supabase/schemas/` as its baseline
|
||||
- Review every generated migration file before committing it
|
||||
|
||||
## 4. **Schema File Organization**
|
||||
## 5. **Schema File Organization**
|
||||
|
||||
- Schema files are executed in lexicographic order. To manage dependencies (e.g., foreign keys), name files to ensure correct execution order
|
||||
- File names and directory layout are for readability only. The engine analyzes dependencies between statements (foreign keys, views over tables, functions used by triggers) and orders them automatically. Do not rely on lexicographic file ordering to manage dependencies
|
||||
- When adding new columns, append them to the end of the table definition to prevent unnecessary diffs
|
||||
- Reserve the `supabase/schemas/_custom/` directory for hand-authored SQL covering object kinds the engine does not track (see known caveats). Create the directory yourself. The CLI never creates, overwrites, or prunes it
|
||||
|
||||
## 5. **Rollback Procedures**
|
||||
## 6. **Rollback Procedures**
|
||||
|
||||
- To revert changes
|
||||
- Manually update the relevant `.sql` files in `supabase/schemas/` to reflect the desired state
|
||||
- Generate a new migration file capturing the rollback
|
||||
```bash
|
||||
supabase db diff -f <rollback_migration_name>
|
||||
```
|
||||
- Review the generated migration file carefully to avoid unintentional data loss
|
||||
- To revert a change that has **not** been deployed, reset the local database to a previous migration version, then edit the schema files and regenerate a single migration:
|
||||
```bash
|
||||
supabase db reset --version <timestamp>
|
||||
supabase db schema declarative sync -f <migration_name>
|
||||
```
|
||||
- To revert a change that **has** been deployed, first update the relevant `.sql` files in `supabase/schemas/` to reflect the desired state, then generate a new forward migration:
|
||||
```bash
|
||||
supabase db schema declarative sync -f <rollback_migration_name>
|
||||
```
|
||||
- Review the generated migration file carefully to avoid unintentional data loss. Down migrations are usually destructive
|
||||
|
||||
## 6. **Known caveats**
|
||||
## 7. **Known caveats**
|
||||
|
||||
The migra diff tool used for generating schema diff is capable of tracking most database changes. However, there are edge cases where it can fail.
|
||||
|
||||
If you need to use any of the entities below, remember to add them through versioned migrations instead.
|
||||
Schema diffs are generated by the `pg-delta` engine, which models most database entities, including tables, views, materialized views, functions, triggers, RLS policies, grants, comments, domains, partitions, and publications. The cases below are not captured.
|
||||
|
||||
### Data manipulation language
|
||||
|
||||
- DML statements such as insert, update, delete, etc., are not captured by schema diff
|
||||
- DML statements such as `insert`, `update`, and `delete` are never captured by a schema diff. This includes storage buckets, which are rows in `storage.buckets`, not schema objects
|
||||
- A DML statement inside a declarative schema file is an error. Keep data changes in seed files or hand-written versioned migrations
|
||||
|
||||
### View ownership
|
||||
### Untracked object kinds
|
||||
|
||||
- view owner and grants
|
||||
- security invoker on views
|
||||
- materialized views
|
||||
- doesn’t recreate views when altering column type
|
||||
- The engine does not track: casts, operators, operator classes and families, text search configurations, dictionaries, parsers, and templates, statistics objects, languages, transforms, and parameter ACLs. The engine reports them as warnings instead of silently dropping them
|
||||
- To use these objects, put their SQL in the reserved `supabase/schemas/_custom/` directory so dependent objects still resolve, and deliver the change itself through a versioned migration. That migration must sort before the generated migration that depends on the object, or `db reset` and later `sync` runs fail
|
||||
- Exception: manage parameter ACLs through versioned migrations only. Do not put them in `_custom/`
|
||||
|
||||
### RLS policies
|
||||
### Supabase-managed schemas
|
||||
|
||||
- alter policy statements
|
||||
- column privileges
|
||||
- Other entities#
|
||||
- schema privileges are not tracked because each schema is diffed separately
|
||||
- comments are not tracked
|
||||
- partitions are not tracked
|
||||
- alter publication ... add table ...
|
||||
- create domain statements are ignored
|
||||
- grant statements are duplicated from default privileges
|
||||
- Platform objects in Supabase-managed schemas (such as `auth` and `storage`) are excluded from diffs, but your own customizations on top of them are captured: triggers on managed tables whose trigger function lives outside the managed schemas (for example, a trigger on `auth.users` that calls a function in `public`), RLS policies on any table in `auth`, and RLS policies on `storage.objects`, `storage.buckets`, and `realtime.messages`. A trigger whose function lives inside `auth` or `storage` is excluded even if you created the function; deliver it through a versioned migration. Other objects you create inside these schemas, such as your own functions or indexes, are not diffed. Manage those through versioned migrations
|
||||
|
||||
### Extension-managed objects
|
||||
|
||||
- Objects that extensions create and manage, such as partitions maintained by `pg_partman` and queue tables created by `pgmq`, are never emitted as raw `create table` or `drop table` statements. Changes to them appear as calls to the extension's own API (for example `select pgmq.drop_queue('q');`), and the CLI flags those as destructive. Create and change these objects through the extension's own functions and review any generated API calls
|
||||
|
||||
### Legacy `migra` engine
|
||||
|
||||
- If `[experimental.pgdelta]` is not enabled, the project falls back to the legacy `migra`-based workflow (`supabase stop`, then `supabase db diff -f <migration_name>`), which has additional limitations around view owners and grants, security invoker on views, `alter policy`, column privileges, comments, publication membership, roles, and domains. Enable `pg-delta` instead of following that flow
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in new issue
Block a user