Overview
Environment Sync moves schema and configuration between Directus instances (development to staging, staging to production) through JSON files you commit to git. It ships as part of the Directus CLI (directus-cli, or its short alias d6s).
pull writes files from a source instance, diff previews what a push would change, and push applies the files to a target:
d6s sync pull --from staging # snapshot schema + configuration into committed files
d6s sync diff --to production # read-only preview of what a push would change
d6s sync push --to production # apply schema, then import configuration records
d6s sync # interactive wizard: pull, then push
Because the files live in your repository, your normal review workflow applies: schema changes show up in pull requests, environments converge through git history, and a bad change is a revert away from being found. The files are the record; restoring a database still requires a backup.
What syncs
A pull touches two axes, and the CLI reports each:
Schema 24 collections → directus/default/schema
Resources 206 records in 10 resources → directus/default/data
| Axis | What it covers | Default | Scope it with |
|---|---|---|---|
| Schema | Every collection, field, and relation, including custom fields on system collections and collection folders. | Full snapshot | --collections / --exclude-collections / --no-schema |
| Configuration resources | Records of directus_* configuration tables: roles, policies, access, permissions, flows, operations, dashboards, panels, settings, and media-library folders. | 10 resource types | --<resource> / --no-<resource> / --all |
| Users | Accounts, with all secret columns stripped. | Opt-in (--users) | --users or --all |
| Translations | Custom translation strings. | Opt-in (--translations) | --translations or --all |
Your own collections' content, the rows in the tables you create, is not synced. Environment Sync is for the shape of a project and its configuration, not its data.
The committed files
Artifacts land in a directory you commit: one JSON file per collection, written deterministically so a re-pull with no changes is byte-identical and diffs only ever show real changes:
directus/<project>/
schema/ # the schema snapshot, split per collection
data/ # configuration records per resource
id_map.json # committed source → target record identity map
The metadata.json manifest in each directory records which files the CLI owns. The CLI never deletes a file it did not write.
Safety model
Environment Sync is built around a small set of promises:
diffapplies nothing. It previews the schema change and dry-runs the data import server-side, then rolls back.- Deletions are gated. Only
mirrormode deletes, and deleting always requires explicit consent:--dangerously-allow-deletein automation, or typing the profile name interactively.--yesnever authorizes a deletion. - Identity is never guessed. Records are matched across instances by the committed id map and natural keys. An ambiguous match prompts in a terminal and refuses in CI. It is never resolved by picking the first candidate.
- Stored secrets never land in committed files. Built-in secret columns and fields you mark concealed, hashed, or encrypted are stripped at export. One warned exception: custom headers in flow request operations export verbatim.
- Failures are loud. Hand-edited files, corrupt manifests, truncated fetches, and version mismatches stop the command with a named error rather than degrading silently; an export the source itself curtailed is marked incomplete and refused at mirror push. A full re-pull converges the files again.
Next steps
Get once-a-month release notes & real‑world code tips...no fluff. 🐰