CLI

Sync policies

Control who wins when local .env and Shelve diverge — push guards, pull merge, and diff.

Sync policies live under sync in shelve.json (and can be enforced on the server per project). They answer: should a push from my laptop overwrite production? Does pull replace my whole .env or merge?

Quick example

shelve.json
{
  "$schema": "https://shelve.cloud/schema.json",
  "slug": "my-team",
  "project": "my-app",
  "defaultEnv": "development",
  "sync": {
    "protectedEnvironments": ["production", "preview"],
    "default": {
      "onPushConflict": "overwrite",
      "pullMode": "replace"
    },
    "environments": {
      "development": {
        "sourceOfTruth": "local",
        "onPushConflict": "overwrite"
      },
      "production": {
        "sourceOfTruth": "remote",
        "allowPush": false,
        "pullMode": "merge"
      }
    }
  }
}

Policy fields

FieldValuesEffect
sourceOfTruthremote | localHint for shelve sync: pull when remote, push when local.
onPushConflictoverwrite | skip | fail | promptWhen a key exists on Shelve with a different value than local. Default: overwrite.
pullModereplace | mergereplace: rewrite .env (legacy). merge: remote keys win; local-only keys are kept.
allowPush / allowPullbooleanHard block with PUSH_BLOCKED / PULL_BLOCKED.
protectedEnvironmentsstring[]Sets allowPush: false for listed env names.
requireConfirmationbooleanExtra confirmation even if confirmChanges is false.

Per-environment overrides go in sync.environments.<name>. Defaults apply via sync.default.

Server policies

Project Settings → Sync policy stores syncPolicy on the project. Server rules cannot be relaxed from shelve.json: if the server sets allowPush: false, the CLI cannot override it.

Protected environments reject API writes with ENV_PROTECTED.

Commands

shelve diff

Compare local envFileName with Shelve (no writes). Safe for agents with --json (no secret values).

terminal
shelve diff --env staging
shelve --json diff --env staging
shelve diff --env staging --show-values

shelve sync {#sync-command}

Apply the effective policy for the environment:

  • sourceOfTruth: remote → pull (respects pullMode)
  • sourceOfTruth: local → push (respects onPushConflict)
terminal
shelve sync --env development
shelve sync --env production --dry-run
shelve sync --yes --env staging

--dry-run reports the planned action and diff without writing.

Environment variables

VariableEffect
SHELVE_SYNC_ALLOW_PUSH=0Disables push for all environments in this process
SHELVE_SYNC_ALLOW_PULL=0Disables pull for all environments

Error codes

CodeMeaning
PUSH_BLOCKEDallowPush: false or protected environment
PULL_BLOCKEDallowPull: false
SYNC_CONFLICTonPushConflict: fail (or prompt in non-interactive mode)
ENV_PROTECTEDServer rejected a write to a protected environment

See Troubleshooting.

Monorepos

Put protectedEnvironments in the root shelve.json; package-level files can override sync.environments for each app.