Diffing & Pushing
With a snapshot pulled and committed, diff previews what applying it to a target would change, and push applies it. Both commands read the committed files: what you push is what is in git, not what is currently on the source instance.
Previewing with diff
d6s sync diff --to production
diff applies nothing. It previews the schema change, then has the target server dry-run the data import and roll it back, so the data plan is the server's own answer, not a client-side guess.
Every preview opens by naming the target instance and what the mode would mean (merge — additive, no deletions), then lists schema changes line by line and the data plan per collection (+N new ~N updated).
One thing a diff never does is guess: a committed record that could match more than one target record is reported as unresolved, not previewed as a create. An interactive push resolves it by asking you; a push in CI refuses. See record identity below.
Push modes
d6s sync push --to production # merge (the default)
d6s sync push --to production --mode mirror # deletes, behind the gates below
| Mode | Schema | Data | Deletes? |
|---|---|---|---|
add | Additive | Inserts only; existing records are never updated | No |
merge (default) | Additive | Creates and updates | No |
mirror | May delete in scope | Creates, updates, and deletes records absent from the files | Yes, gated |
mirror push applies that stale state to the target. Run a full pull first.Deletion gates
Only mirror deletes, and deleting always requires its own explicit consent:
| Context | To delete you must |
|---|---|
| Interactive terminal | Review the plan naming the losses, then type the profile name (unless you passed --dangerously-allow-delete, which is the consent) |
| Non-interactive / CI | Pass --dangerously-allow-delete |
--yes skips the ordinary confirmation prompt, but it never authorizes a deletion. A mirror push in CI without --dangerously-allow-delete refuses before changing anything.
How a push runs
A push applies in two phases, schema first:
- Schema. The schema change applies first, sealed with a hash of the target's schema. If the target changed between planning and applying, the push stops instead of applying a stale plan.
- Data. Configuration records import once the schema is in place.
The two phases are not one transaction. If the data import fails after the schema applied, run the push again: the schema now matches, so the re-run applies data alone.
Record identity
The same role or flow carries different primary keys on each instance, so records have to be matched across them. Two mechanisms decide which target record a committed record is:
- The committed identity map. Each push records source-to-target pairs in
directus/<project>/id_map.json. Commit it; it is how the next push updates a record instead of creating a duplicate. - Natural keys. A record not yet in the map is matched to a target record by a natural key: its name for most resources, its email for a user, its key for an operation.
Ambiguity is never resolved by guessing. When two target records could both be the match, the CLI prompts you to choose in a terminal, and refuses in CI.
The first push into a target seeded from the same template can ask a few of these identity questions about pairs of records that plausibly are the same one. That is expected: answer them, the answers land in the identity map, and the questions do not come back. It converges in one pass.
Version matching
Schema changes require the snapshot's Directus version and the target's version to match exactly, patch release included. A mismatch refuses the command and names both versions. Align the instances (re-pull if the source was upgraded), or pass --allow-version-drift to override the gate, which proceeds with a loud warning. The CLI does not translate schema between versions.
Convergence
A push that applied cleanly leaves nothing behind:
d6s sync push --to production
# → schema and data match; nothing to push.
Re-running a completed push is safe, and the clean state is verified against the target, not assumed. If a connection drops mid-import and the result is unknown, the CLI says so. Run d6s sync diff before retrying rather than risking a blind retry.
Get once-a-month release notes & real‑world code tips...no fluff. 🐰
Pulling
Snapshot schema and configuration from a source instance into files you commit. Scope a pull by resource or by collection, or skip schema entirely for configuration-only projects.
CI & Automation
Run Environment Sync unattended with tokens from environment variables, machine-readable JSON reports on stdout, and explicit flags in place of prompts.