docs: clarify declarative pg_cron job workflow (#51596)

## Problem

The declarative schemas guide does not explain how pg-delta tracks
pg_cron jobs. Its guidance that schema diffs exclude row data can also
suggest that jobs stored in cron.job are excluded.

Readers need to know where to declare jobs, how changes become
migrations, and why jobs without unique names are skipped.

## Solution

Document the declarative workflow for pg_cron jobs, including:

- Declaring jobs in SQL files under supabase/schemas/.
- Giving each job a unique name.
- Generating migrations when job declarations change or are removed.
- The scheduling and unscheduling calls emitted by the engine.

Connect the DML caveat to the extension configuration explanation so
readers understand why supported configuration rows are tracked.

Validation: Prettier, Markdown generation, and git diff --check passed.
The cron workflow was checked against source code but was not executed
in a sandbox.

## Review instructions

1. Open the declarative database schemas guide in the docs preview.
2. Read Data manipulation language and follow the extension
configuration link.
3. In Extension-managed objects, confirm that the cron guidance explains
where to declare jobs, the naming requirement, and the generated
migration behavior.
4. Follow generate and apply a migration and confirm it leads to the
existing workflow.

## Checklist

- [x] I have read
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
- [x] If I wrote a new docs topic or edited an existing topic, I used
the /write-the-docs or /edit-the-docs skill, which applies the docs
[style
guide](https://github.com/supabase/supabase/tree/master/apps/docs/style-guide)
This commit is contained in:
Wen Bo Xie authored and GitHub committed 2026-10-13 16:45:48 +02:00
1 parent 1b1c495c6a
commit 2ba7352cfe
1 file changed
+5 -1
@@ -309,7 +309,7 @@ Schema diffs are generated by `pg-delta`, which models most database entities, i
### Data manipulation language
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).
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). Supported [extension configuration](#extension-managed-objects), such as named `pg_cron` jobs, is tracked separately through extension functions.
### Default privileges on new objects
@@ -331,6 +331,10 @@ Manage those objects through versioned migrations.
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.
`pg-delta` tracks named `pg_cron` jobs as extension configuration, even though they are stored as rows in `cron.job`. Generated migrations create jobs with `select cron.schedule_in_database(...)` and remove them with `select cron.unschedule(...)`. For a changed job, the migration calls `cron.unschedule(...)` followed by `cron.schedule_in_database(...)`.
With `pg_cron` enabled, declare each job in a SQL file under `supabase/schemas/` using `select cron.schedule('<name>', ...)`. Give each job a unique name. The engine skips jobs with a missing or duplicate `jobname` and reports a warning. To change or remove a job, edit or remove its declaration, then [generate and apply a migration](#updating-your-schema) with `supabase db schema declarative sync`.
### Adopting an existing schema tree
Two checks gate `sync` on a schema tree the CLI didn't generate: