From 90b7a51be431d3d55db0587e22784b45ac2954a3 Mon Sep 17 00:00:00 2001 From: Christopher Jennings <1398135+ChristopherJennings@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:38:27 -0400 Subject: [PATCH 1/2] Fix schema apply request body in migration tutorial The REST API tab told readers to POST the snapshot response body to /schema/apply. That endpoint consumes the diff, not the snapshot: api/src/controllers/schema.ts types the apply body as SnapshotDiffWithHash and passes it to service.apply(). Following the tutorial as written fails. The Node.js tab on the same page already did this correctly with schemaApply(diff), so the two tabs contradicted each other. Pre-existing error, unrelated to any specific release. Co-Authored-By: Claude Fable 5 --- .../promoting-changes-between-environments-in-directus.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/tutorials/4.migration/promoting-changes-between-environments-in-directus.md b/content/tutorials/4.migration/promoting-changes-between-environments-in-directus.md index a9b4697b..a070ab49 100644 --- a/content/tutorials/4.migration/promoting-changes-between-environments-in-directus.md +++ b/content/tutorials/4.migration/promoting-changes-between-environments-in-directus.md @@ -220,7 +220,7 @@ You should have two Directus projects - this guide will refer to them as the "ba #### Apply Diff To Target Project - Perform a `POST` request to `/schema/apply?access_token=`, with the "Content Type" header set to `application/json` and the body set to the contents of the `data` property of JSON response from the snapshot. + Perform a `POST` request to `/schema/apply?access_token=`, with the "Content Type" header set to `application/json` and the body set to the contents of the `data` property of the JSON response from the diff. Note the response status of 204, which indicates a successful data model migration. From a93dc67e7a5d068c7d73049903decd81d9775348 Mon Sep 17 00:00:00 2001 From: Christopher Jennings <1398135+ChristopherJennings@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:50:54 -0400 Subject: [PATCH 2/2] Document the v12.2.0 schema snapshot and diff parameters Verified against the v12.2.0 tag. - Partial snapshots via includeCollections/excludeCollections (api/src/controllers/schema.ts rejects both together; resolve-scoped-collections.ts filters strictly and ignores unknown names, so it does not pull in related collections). A scoped snapshot is marked version 2, and get-snapshot-diff.ts reads that marker to scope the diff, so applying a partial snapshot never removes collections left out of it - The diff mode parameter: mirror is the default, merge omits operations that would delete a collection, field, or relation - schemaDiff now takes an options object. v12.1.1 accepted force as a positional boolean, so the previous instruction to pass force as a second argument no longer works Also drops a stale sentence claiming getSnapshot() destructures a data property, which the surrounding code does not do. It sat where the new snapshot prose goes, so it could not be separated out. Co-Authored-By: Claude Fable 5 --- ...hanges-between-environments-in-directus.md | 55 +++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/content/tutorials/4.migration/promoting-changes-between-environments-in-directus.md b/content/tutorials/4.migration/promoting-changes-between-environments-in-directus.md index a070ab49..9590ceee 100644 --- a/content/tutorials/4.migration/promoting-changes-between-environments-in-directus.md +++ b/content/tutorials/4.migration/promoting-changes-between-environments-in-directus.md @@ -94,8 +94,21 @@ You should have two Directus projects - this guide will refer to them as the "ba } ``` - Note that the data property is destructured from the response and returned. In the `main()` function, call - `getSnapshot()`: + This returns a snapshot of every collection in the project. To promote only part of your data model, scope the + snapshot with `includeCollections` or `excludeCollections`: + + ```js + function getSnapshot() { + return baseDirectus.request(schemaSnapshot({ includeCollections: ['articles', 'authors'] })); + } + ``` + + The two options are mutually exclusive, and collection names that do not exist in the base project are ignored. A + scoped snapshot is a partial snapshot, marked with `version: 2` instead of `version: 1`. The diff step reads that + marker and limits itself to the collections the snapshot contains, so applying a partial snapshot never removes + collections that were left out of it. + + In the `main()` function, call `getSnapshot()`: ```js async function main() { @@ -131,6 +144,20 @@ You should have two Directus projects - this guide will refer to them as the "ba Get your diff by running `node index.js`. + By default the diff mirrors the base project: anything the target has that the base does not is marked for + deletion. Pass `mode: 'merge'` to get an additive diff instead, which omits operations that would delete a + collection, field, or relation: + + ```js + function getDiff(snapshot) { + return targetDirectus.request(schemaDiff(snapshot, { mode: 'merge' })); + } + ``` + + Use `merge` when the target project holds collections the base project should not remove, such as a production + environment with its own reporting tables. Use the default `mirror` mode when the base project is the single source + of truth for the whole data model. + #### Apply Diff To Target Project At the bottom of `index.js`, create a `applyDiff()` function which accepts a `diff` parameter: @@ -157,8 +184,14 @@ You should have two Directus projects - this guide will refer to them as the "ba ### Handling Different Directus Versions The diff endpoint does not allow different Directus versions and database vendors by default. This is to avoid any - unintentional diffs from being generated. You can opt in to bypass these checks by adding a second query parameter - called `force` with the value of `true`. + unintentional diffs from being generated. You can opt in to bypass these checks by passing `force: true` alongside + the other diff options: + + ```js + function getDiff(snapshot) { + return targetDirectus.request(schemaDiff(snapshot, { force: true })); + } + ``` The hash property in the diff is based on the target instance's schema and version. It is used to safeguard against changes that may happen after the current diff was generated which can potentially incur unexpected side effects when @@ -210,6 +243,14 @@ You should have two Directus projects - this guide will refer to them as the "ba Copy the JSON response with your data model snapshot. + To promote only part of your data model, scope the snapshot with either `includeCollections` or `excludeCollections`, passing a comma-separated list of collection names. The two parameters cannot be used together. + + ``` + GET /schema/snapshot?includeCollections=articles,authors + ``` + + A scoped snapshot is a partial snapshot, marked with `version: 2` instead of `version: 1`. The diff step reads that marker and limits itself to the collections the snapshot contains, so applying a partial snapshot never removes collections that were left out of it. + #### Retrieve Data Model Diff This section will create a "diff" that describes all differences between your source and target project's data models. @@ -218,6 +259,12 @@ You should have two Directus projects - this guide will refer to them as the "ba Copy the JSON response with your data model diff. + By default the diff mirrors the source project, so anything the target has that the source does not is marked for deletion. Add `mode=merge` for an additive diff, which omits operations that would delete a collection, field, or relation. The default is `mode=mirror`. + + ``` + POST /schema/diff?mode=merge + ``` + #### Apply Diff To Target Project Perform a `POST` request to `/schema/apply?access_token=`, with the "Content Type" header set to `application/json` and the body set to the contents of the `data` property of the JSON response from the diff.