Skip to main content

Environment variables

Every variable the CLI and SDK read. All are optional — the defaults in the right column are what you get when the variable is unset. Authentication (see Signing in & deploying for the full precedence ladder) xanots preflight — its own target, deliberately separate from the deploy login Output & diagnostics Update notifier Escape hatches
process.env read inside a workspace definition is a different thing entirely: it resolves at export time and bakes the literal into the bundle. For a value the deployed stack reads at runtime, use workspaceConfig({ env }) + env("NAME").

Identity & the xano.lock file

Every top-level object carries a stable guid — Xano’s identity anchor. On a sync import the engine matches an incoming object to an existing one by guid and updates it in place; no match means a new object. So re-running export/deploy on the same code maps cleanly onto the same workspace — no duplicates. By default the guid derives from the object’s name — for a query, from its api group, verb, and name together, which is the engine’s own uniqueness for an endpoint, so GET items and POST items are distinct objects and a path may repeat across groups. Set an explicit guid to pin identity across a rename, or to adopt an existing workspace object into code. The opt-in xano.lock freezes the whole workspace’s identities at once — every auto-derived guid, plus the canonical URL tokens of API groups and toolsets (which the engine otherwise randomizes, giving the same code different public URLs per environment). Create it once with xanots export ./xano/index.ts --lock; from then on it’s read automatically and updated on every export (written atomically before the bundle). Commit it next to your code. A project from xanots init is locked from its first export — both its xano:export and xano:deploy scripts pass --lock, and npm run xano:check is the --frozen-lock CI guard. Adopt it early either way: once identities have drifted, the only way back is lock import against the deployed workspace. Precedence at emit is always explicit in-code value → lock entry → name derivation. When the lock is actually load-bearing. Because the default derivation is deterministic — md5("<type>:<name>"), and md5("query:<group>|<verb>|<name>") for a query — a project that created all of its own objects can regenerate a byte-identical lock from its own source. Delete that lock, release again, and the same guids come back: the objects match and update in place. For that project the lock is a cache, and losing it costs nothing. The lock is load-bearing exactly where a live guid diverges from that derivation, which happens two ways:
  • Adopted objects — anything built in the Xano UI first and taken over with lock import. The engine assigned those guids randomly; nothing in your code can re-derive them.
  • Renamed objects — lock rename pins the original guid under the new name, so the derivation no longer reproduces it.
For those entries the lock is irreplaceable, and losing it means the next release matches nothing and creates a duplicate of every diverged object. A workspace adopted wholesale from the UI can be almost entirely divergent, so treat that lock as the critical artifact. Either way, commit it — the cache is worth having, and you generally will not know which entries have diverged without looking. Renames — with a lock, a rename in code no longer means delete+create on sync. The export warns about the orphaned entry and names the fix-up:
rename/adopt take no entry file, so on their own they look for xano.lock in the current directory. Pass --entry=<path> to derive it beside the entry the way export/deploy/prune do, or --lock=<path> to name the file outright. They never reach for a lock you did not point them at — when they spot one next door they say so and stop, rather than writing a file you did not name. After --replace — a replace rebuilds the workspace with fresh engine identities, so the lock is stale the moment it finishes and the next ordinary release would match nothing and try to create everything. xanots release ./xano/index.ts --replace now re-pins the lock from the rebuilt workspace itself and tells you to commit it. If there is no lock to re-pin, it says so — without one, the next release duplicates every object. Importing a live workspace’s identitiesxanots lock import <bundle.json> seeds the lock from a real engine packageExport, capturing the live workspace’s random guids by (type, name) so code takes over an existing workspace and the first sync updates in place instead of duplicating. CIxanots export ./xano/index.ts --frozen-lock fails instead of changing the lock, so a canonical minted in a throwaway container can never silently diverge public URLs. Mint locally, commit the lock.