Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion content/guides/10.environment-sync/0.index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The CLI is built to be safe to point at production: `diff` never applies anythin
## What syncs

- **Schema**: every collection, field, and relation, including custom fields on system collections.
- **Configuration**: roles, policies, access, permissions, flows, operations, dashboards, panels, settings, media-library and flow folders, and custom Data Studio translation strings.
- **Configuration**: roles, policies, access, permissions, flows, operations, dashboards, panels, settings, global and role presets (bookmarks and default views), media-library and flow folders, and custom Data Studio translation strings.
- **Opt-in**: user accounts, with every secret field stripped.

Unlike a full schema snapshot, a pull is not all-or-nothing. `--collections posts` narrows which Schema files it overwrites, and resource flags like `--flows` or `--no-schema` choose which Configuration files it touches. That is how you promote finished work from a shared development instance while unfinished work stays out of the sync files entirely. Scope is by collection and resource type, not by individual record. See [Promote only the changes that are ready](/guides/environment-sync/common-workflows#promote-only-the-changes-that-are-ready).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ The server never hands out the real value for these fields: concealed fields rea

## System collections that do not sync

None of these sync today. Some are shared configuration that a future release could take on; the rest are per-instance state that a sync should never touch.
None of these sync today, apart from the shared presets noted below. Some are shared configuration that a future release could take on; the rest are per-instance state that a sync should never touch.

| Collection | Why it doesn't sync |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `directus_presets` | Bookmarks, saved layouts, and Insights presets mix shared configuration with personal preference. A future release may sync the shared part. |
| `directus_presets` | Personal presets: the bookmarks and saved layouts that belong to one user. Global and role presets sync as the `presets` resource. |
| `directus_extensions` | The enabled/disabled state of installed extensions is tied to what is physically deployed on each instance. Deploy extensions to the target before pushing schema or flows that depend on them; the push itself does not warn. |
| `directus_files` | File-interface **fields** sync as Schema; file records and the binaries behind them are their own workstream. |
| `directus_comments` | Content comments; per-instance state. |
Expand Down Expand Up @@ -64,4 +64,7 @@ None of these sync today. Some are shared configuration that a future release co
- **Users without an email address fail import.** The server's import validation rejects a user with no email, so a `--users` push containing one fails before any Configuration changes apply. Give the account an email on the source, or remove it, first.
- **Panels can duplicate on a first sync into a look-alike target.** Panels have no name to match on, so pushing into a target that already holds equivalent panels (seeded from the same template) can create them a second time. The ID map prevents repeats after that first push.
- **A mirror push of users does not protect your own account.** If users are in the sync files and the account the push authenticates with is absent from them, a `mirror` push orders its deletion like any other record; the CLI has no self-protection, and whether the server refuses is up to the server. When you sync users, make sure the sync files include the accounts your pushes run as.
- **Preset filters keep their source IDs.** A preset whose filter or layout names a specific user, role, or item by ID is copied as-is, so it may match nothing on the target. Dynamic values such as `$CURRENT_USER` work on any instance.
- **Role presets need their role linked.** A preset scoped to a role the target can't identify is skipped with a warning. That includes a role created by hand on the target with the same name, because a presets-only pull carries role IDs, not names. Pull with `--roles --no-deps` and push again: roles are matched by name, and their policies stay out. A matched role's icon, description, and parent are updated from the source. In `mirror` mode, roles that exist only on the target are deleted.
- **Presets can arrive before their collection.** Like permissions, a preset can be pushed for a collection the target doesn't have yet, for example with `"schema": false`. It's created without an error and takes effect once the collection exists.
- **A Configuration diff can leave harmless gaps in PostgreSQL integer IDs.** The target server dry-runs the import and rolls it back, but PostgreSQL sequences do not roll back. No records are created or changed; only a sequence such as the one for `directus_permissions` can advance.
17 changes: 11 additions & 6 deletions content/guides/10.environment-sync/6.reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ d6s sync pull --from <profile> [scope flags]
| `--no-deps` | Do not add prerequisites; resources owned by a selected parent remain included |
| `--project <name>` | Project to sync (default: `default`) |

A bare pull includes every selectable resource except users. This means translations sync by default. Pass `--no-translations` to exclude them, or `--translations` to pull only translations.
A bare pull includes every selectable resource except users. This means translations and presets sync by default. Pass `--no-translations` or `--no-presets` to exclude either one, or `--translations` to pull only translations.

The selectable resources are `roles`, `policies`, `flows`, `dashboards`, `settings`, `folders`, `users`, and `translations`. The CLI automatically includes `access`, `permissions`, `operations`, and `panels` with their parent resources (see [the dependency table](#configuration-resources)). `--flows` also brings `folders`, because the folder a flow lives in is part of its identity. Folders differ from the automatic resources in one way: `folders` is selectable in its own right, so `--no-deps` drops it from a `--flows` selection while `operations` still comes. Positive selection (`--flows`) cannot be combined with `--all` or with `--no-` flags. An exclusion that a retained resource depends on is refused rather than silently overridden: `--no-policies` alone fails because `roles` requires policies and would pull them back, so pass `--no-roles` as well, or keep policies. `--no-folders` alone fails for the same reason, because `flows` requires folders. Resource selection never narrows the schema; the two axes are scoped independently.
The selectable resources are `roles`, `policies`, `flows`, `dashboards`, `settings`, `folders`, `presets`, `users`, and `translations`. The CLI automatically includes `access`, `permissions`, `operations`, and `panels` with their parent resources (see [the dependency table](#configuration-resources)). `--flows` also brings `folders`, because the folder a flow lives in is part of its identity. Folders differ from the automatic resources in one way: `folders` is selectable in its own right, so `--no-deps` drops it from a `--flows` selection while `operations` still comes. Positive selection (`--flows`) cannot be combined with `--all` or with `--no-` flags. An exclusion that a retained resource depends on is refused rather than silently overridden: `--no-policies` alone fails because `roles` requires policies and would pull them back, so pass `--no-roles` as well, or keep policies. `--no-folders` alone fails for the same reason, because `flows` requires folders. Resource selection never narrows the schema; the two axes are scoped independently.

Two warnings a scoped pull can raise, neither of which widens the scope for you:

Expand Down Expand Up @@ -232,6 +232,7 @@ Resource selection follows a dependency graph: selecting a resource pulls in wha
| `settings` | Yes | `--settings` | — | A single record. License and AI credentials, branding images (logos, backgrounds, favicon), and the default storage folder are stripped. |
| `folders` | Yes | `--folders` | — | Both folder trees. Media-library folders and flow folders share `directus_folders` and are told apart by their `type`. Distinct from collection folders (Data Studio sidebar groups), which sync as Schema. |
| `translations` | Yes | `--translations` | — | Matched by `language` and `key`; on Directus 12.2.0 and later, `merge` and `mirror` can update existing strings. |
| `presets` | Yes | `--presets` | — | Global and role bookmarks and default views. Personal presets are never pulled; a `mirror` push keeps them on the target, along with presets of never-synced roles. A role preset is skipped with a warning until its role is linked. |
| `users` | Opt-in | `--users` | `roles`, `policies` | Secret fields (`password`, `token`, `tfa_secret`, and others) are stripped. |

::callout{icon="i-lucide-triangle-alert" color="warning"}
Expand Down Expand Up @@ -298,6 +299,7 @@ Records are matched across instances first by the ID map (`<directory>/<project>
| Permissions | `policy`, `collection`, and `action` |
| Operations | `flow` and `key` |
| Translations | `language` and `key` |
| Presets | `collection`, `bookmark`, and `role` |
| Settings | The single settings record |
| Panels | Nothing; ID map only |

Expand Down Expand Up @@ -346,6 +348,7 @@ With `--json`, stdout carries exactly one report per command; warnings still go
"dashboards",
"permissions",
"policies",
"presets",
"roles",
"settings",
"translations"
Expand All @@ -359,13 +362,14 @@ With `--json`, stdout carries exactly one report per command; warnings still go
"directus_dashboards",
"directus_permissions",
"directus_policies",
"directus_presets",
"directus_roles",
"directus_settings",
"directus_translations"
],
"recordCount": 57,
"collectionCount": 11,
"fileCount": 12,
"collectionCount": 12,
"fileCount": 13,
"removed": [],
"incomplete": []
}
Expand Down Expand Up @@ -406,12 +410,13 @@ The Schema counters (`collections` through `files`) are `null` when the Schema p
"dependent": 0
},
"unchanged": 0,
"incomplete": []
"incomplete": [],
"skipped": 0
}
}
```

`changes` is `true` when a push would do anything, including when `data.reconciliation.ambiguous` is non-zero. `added`/`modified`/`deleted` count Schema items. `data.resultsByCollection` is the target server's own per-collection dry-run answer. Reconciliation separates records that matched, have no match, need a choice, or depend on a choice; `unchanged` counts matched records whose synced values already agree.
`changes` is `true` when a push would do anything, including when `data.reconciliation.ambiguous` is non-zero. `added`/`modified`/`deleted` count Schema items. `data.resultsByCollection` is the target server's own per-collection dry-run answer. Reconciliation separates records that matched, have no match, need a choice, or depend on a choice; `unchanged` counts matched records whose synced values already agree. `skipped` counts records left out because the target can't take them yet, such as role presets whose role doesn't exist there.

`d6s sync push --to production --yes --json` reports the same top-level shape and adds `applied`, which is `true` when the push changed the target. Its `data.resultsByCollection` reflects what the import actually did; `data.reconciliation` and `data.unchanged` are `null` because push reports applied results rather than diff-only comparison counts.

Expand Down
Loading