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.envread 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, useworkspaceConfig({ env })+env("NAME").
Identity & the xano.lock file
Every top-level object carries a stableguid — 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 renamepins the original guid under the new name, so the derivation no longer reproduces it.
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 identities — xanots 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.
CI — xanots 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.