Secrets & Limitations
How secrets are handled
A pull exports real records: the settings row, user accounts, flow definitions. If any of those carried a secret value, it would land in JSON files you commit, and git history keeps it forever, in every clone of the repository. Environment Sync strips secret values at export:
- Built-in secret columns (password hashes, tokens, 2FA seeds, license and AI keys) are always deleted from the export.
- Fields you created and marked concealed, hashed, or encrypted are deleted too. Every pull fetches the server's complete field list and drops any flagged value, printing a line naming each dropped field. A field missing from the export reads as protection, not data loss.
Because the field list is fetched separately from the schema, the check also covers pulls scoped to a few collections and pulls that skip schema entirely. And if the check itself cannot run, the pull stops rather than continue unprotected.
The field definition still syncs as schema: the column and its concealed setting arrive on the target. Only the value stays behind; set the real secret on each instance directly.
Why strip instead of sync
The server never hands out the real value for these fields: concealed fields read back as **********, hashed fields as the hash. Exporting that and pushing it would overwrite the target's working secret with a mask. Stripping protects both the repository and the target.
The one blind spot
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 data 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_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 rows and the binaries behind them are their own workstream. |
directus_comments | Content comments; per-instance data. |
directus_activity | The audit log; per-instance data. |
directus_revisions | Change history; per-instance data. |
directus_versions | Content-versioning drafts; per-instance data. |
directus_notifications | User notifications; per-instance data. |
directus_shares | Public share links; per-instance data. |
directus_sessions | Active login sessions; per-instance data. |
directus_migrations | The database migration ledger. The CLI never runs migrations or changes the Directus version. |
directus_webhooks | Deprecated in Directus; superseded by flows. |
What it does not do
| Won't | Because / instead |
|---|---|
| Sync your collections' content (rows) | Environment Sync moves the shape of a project and its configuration. Content sync is deferred to a future release. |
| Undo a push | Revert the commit and push again; removals need mirror. See Roll back a bad push. Only a database backup covers content. |
| Auto-expand a scoped snapshot | A scope pulls exactly what you name. Dangling references produce a warning; widen --collections yourself. |
| Translate schema across versions | A version mismatch refuses the command; --allow-version-drift overrides the gate but converts nothing. |
| Wrap schema and data in one transaction | Schema applies first, then data. A failed import re-runs data alone; see How It Works. |
| Select individual records | Resource selection is by type (--roles), never by row. |
| Model code-first | Model in the Data Studio and pull. Don't hand-author the JSON files. |
| Seal the data plan against target drift | Only the schema apply is sealed against the target changing between preview and apply. The data preview is the server's own dry-run answer, but it is advisory. |
Known limitations
- Translations mirror is opt-in. A server limitation currently breaks
mirrorpushes of translations, so translations are excluded from pulls by default. Opt in with--translations;mergeandaddpushes work normally. - Unlicensed custom permission rules are invisible to the export. On an instance without a license, the API hides custom permission rules, so a pull cannot export them. The pull detects the shortfall and marks the export incomplete:
mergeandaddpush normally,mirrorrefuses. License the source instance to export them. - Users without an email address fail import. The server's import validation rejects a user with no email, so a
--userspush containing one fails before any data applies. 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 identity map prevents repeats after that first push.
- A mirror push of users does not protect your own account. If users are committed and the account the push authenticates with is absent from them, a
mirrorpush 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 committed set includes the accounts your pushes run as.
Get once-a-month release notes & real‑world code tips...no fluff. 🐰
CI & Automation
Post the production diff on every pull request and push on merge, with tokens from environment variables, machine-readable JSON reports, and explicit flags in place of prompts.
Reference
Every Environment Sync command and flag, the directus.config.json format, credential resolution, scope tables, push modes, deletion gates, and JSON report formats.