Cloud sync & configuration
Connect your local workspace to a dcupl Console project, then keep the two in sync. The CLI tracks what changed on each side and transfers only the differences — pushes and pulls stay fast, predictable, and never silently clobber edits made on the other side.
Do this first. Every files command needs a project ID and API key. Create a project in the dcupl Console and copy its CLI key (type CLI read/write, see API keys): status, push and pull reject every other key type. Then run dcupl config set once — see Configure credentials below. Without credentials, a command exits 1 with Missing projectId. Set it via `dcupl config set`, the DCUPL_PROJECT_ID env var, or a .env file. (or the same message for apiKey); a key the server refuses gives API key rejected (…). Check your key with `dcupl config set --api-key <key>` ….
How sync works
Sync is a 3-way diff: the CLI compares your local files, the server, and the last-synced baseline to decide what to push, pull, or flag as a conflict. Toggle the mode to see how deletions are handled.
Additive: only new and changed files transfer — nothing is ever deleted.
| File | Local | Server | Action |
|---|---|---|---|
models/Product.dcupl.json | modified | unchanged | |
workflows/sync.workflow-v3.json | added | absent | |
models/Order.dcupl.json | unchanged | modified | |
data/products.csv | modified | modified | |
data/legacy.csv | deleted | present |
The status → review → push loop
files status is read-only — it transfers nothing. Review the diff, then push.
see what differs between local and server — read-only: dcupl files status --json — output: { "success": true, "versionId": "draft", "hasBaseline": true, "uploads": ["models/Product.dcupl.json", "workflows/sync.workflow-v3.json"], "downloads": ["models/Order.dcupl.json"], "conflicts": [{ "path": "data/products.csv", "reason": "both changed" }], "wouldDeleteOnServerInStrictMode": ["data/legacy.csv"], "wouldDeleteLocallyInStrictMode": [], "unchanged": 0, "needsRepair": [] }
a conflict stops the push — resolve it by choosing a winner: dcupl files push --force --path data/products.csv — output: [1/1] ✓ upload data/products.csv Pushed to version: draft Scope: data/products.csv Uploaded (1) ✓ data/products.csv Force-resolved conflicts (1) ! data/products.csv — both changed Unchanged: 0
now push the rest: dcupl files push --json — output: { "success": true, "versionId": "draft", "uploaded": ["models/Product.dcupl.json", "workflows/sync.workflow-v3.json"], "deleted": [], "failed": [], "conflicts": [], "resolvedConflicts": [], "unchanged": 2, "unverified": [] }
Configure credentials
Run dcupl config set once per workspace. Interactive by default; it writes the project ID to dcupl.config.json (workspace config) and your API key to dcupl.secrets.json when that file exists (a dcupl init workspace has one), otherwise to .env as DCUPL_API_KEY, adding .env to .gitignore. Pass flags to skip the prompts for scripts and CI.
# interactive — prompts for project id + API key
dcupl config set
# non-interactive, for scripts and CI
dcupl config set --project-id my-project --api-key <api-key> --yes
# inspect resolved config (key redacted as ***last4)
dcupl config get
dcupl config get --show-secretsCredential precedence. The CLI resolves each value in this order: command flag, where the command has one (--api-key / --project-id for a remote source on dcupl validate, dcupl app create --load and dcupl app loaders add; the files commands have none) → environment variable (DCUPL_API_KEY, DCUPL_PROJECT_ID) → a workspace .env (real environment variables win over it) → the stored dcupl.secrets.json / dcupl.config.json. CI should inject the key via the env var or dcupl config set --api-key, never a committed file. consoleApiUrl has no environment variable — set it with dcupl config set --console-api-url <url>.
Gitignore dcupl.secrets.json before your first commit — it holds your API key (the .gitignore of a new dcupl init folder already lists it and .env). dcupl config set adds .env to .gitignore itself when it writes the key there, and the CLI writes .dcupl/.gitignore (ignoring everything in .dcupl/) together with the sync state, so that state is never committed.
config set flags
| Flag | Purpose |
|---|---|
--project-id <str> | Console project identifier |
--api-key <str> | API key for the project |
--console-api-url <str> | Console API base URL (self-hosted only) |
--yes | Non-interactive; accept defaults and skip prompts |
Config files
| File | Contents | Commit? |
|---|---|---|
dcupl.config.json | Workspace config (project id, baseFolder, paths, filesUpload include/exclude) | Yes |
dcupl.secrets.json | API key | No — gitignore |
.env | DCUPL_API_KEY (written by config set when there is no secrets file; loaded at startup) | No — config set adds it to .gitignore |
dcupl/dcupl.lc.json | Loader config (models, sources) | Yes |
.dcupl/sync-state/ | Local sync ledger | No — ignored by .dcupl/.gitignore, which the CLI writes |
Single-file operations (read, write, delete, move, copy, create-folder) and version management (files versions list, copy, delete) are listed with every flag in the Cloud sync commands.
Resolving conflicts
When both sides changed the same file, sync reports the conflict and stops — there is no auto-merge. Choose a winner with --force: push --force keeps local and overwrites the server; pull --force takes the server and overwrites local.
# both sides edited data/products.csv
dcupl files status
# => Conflicts (1)
# ! data/products.csv — both changed
# (a push now aborts with PUSH_CONFLICTS and exits 1)
# keep your local copy (overwrites the server)
dcupl files push --force --path data/products.csv
# OR take the server copy (overwrites local)
dcupl files pull --force --path data/products.csvVersion resolution
Most commands accept --version (or -v). The CLI resolves the target version in this order:
- 1The explicit
--versionflag, if passed - 2The current HEAD recorded in your sync-state
- 3A fallback of
draft
Only files pull sets HEAD: on the first pull, and when pull --version switches to another version (--dest leaves it alone). Push never moves it, so a workspace that has never pulled pushes to draft. A switch needs a clean workspace or --force; otherwise the pull aborts with PULL_DIRTY_SWITCH.
Pushing to production is rejected. Push to another version, then promote it by copying it: dcupl files versions copy --from draft --to production (this replaces the contents of production).
What can be synced
status, push and pull only see files under the workspace's baseFolder (default dcupl/; paths are relative to it) that match filesUpload.include and not filesUpload.exclude in dcupl.config.json. dcupl init, and dcupl config set when it creates the file, set the include to **/*.json, **/*.csv and **/*.js; add patterns there to sync other allowed files. Run the commands from the workspace root (the folder that holds dcupl.config.json). In a folder without one, they sync dcupl/ with the include patterns **/*.json, **/*.csv and **/*.js and print a notice on stderr, so --json output stays one JSON value.
The dcupl CDN stores text files only. Sync accepts .csv, .json, .txt, .md and .js (scripts, operators, and transformers ship as .js). Any other extension is rejected before a request is sent, and a file whose bytes are not valid UTF-8 is rejected rather than uploaded with mangled content — that applies to files push and to files write --file alike. A rejected file does not stop the rest of the batch; the run exits non-zero.
Large files are handled for you. push uploads files of up to 500 MB each. A larger file fails with File '<path>' is … MB — larger than the 500 MB per-file upload limit. To fix it, split the file. Or leave it out of the push: add it to filesUpload.exclude in dcupl.config.json, or push only the paths you name with --path. On slow links, use --concurrency to lower the default of 4 parallel transfers.
Sync commands
| Command | What it does |
|---|---|
dcupl files status [--version <id>] [--path <p>...] | Show local vs. server differences. Read-only. |
dcupl files push [--version <id>] [--path <p>...] [--strict] [--yes] [--force] [--concurrency <n>] | Upload new and changed files |
dcupl files pull [--version <id>] [--path <p>...] [--strict] [--yes] [--force] [--dest <path>] [--concurrency <n>] | Download new and changed files (--dest: sandbox copy, no sync state change) |
dcupl files list [--search <str>] [--tree] | List server files, filtered or as a tree |
Single-file operations (read, write, delete, move, copy, create-folder) and version management (files versions list, copy, delete) are listed with every flag in the Cloud sync commands.