Repository navigation
Releases: xano-sdk/sdk
Release list
v1.0.10 — The v3 messaging
The README, the project init writes, and the npm listing now tell the same story as xano.com: Xano is one platform to build, run and govern AI-built software. Your coding agent writes the backend in TypeScript, you run it on the Xano Engine, then deploy it to Xano. Nothing changes at runtime.
npm install @xano/sdk@1.0.10The README leads with Write with AI · Run locally · Deploy to Xano
The README opens with "Write your backend in TypeScript. Run it anywhere." and walks the same three steps as the site. A new guardrails section covers export --strict, deploy --test and promote: one set of rules for every person and every agent.
The SDK docs site is linked from the README
sdk.docs.xano.com is in the README's nav, its Reference section and its footer.
The deploy link opens the Xano editor
The AGENTS.md that init writes, and the brief it prints, now say the link a deploy prints opens the Xano editor.
The npm description matches the deploy default
The npm description used to say a deploy goes to an ephemeral. It now describes the current flow: write with your coding agent, run on the Xano Engine, deploy to Xano.
v1.0.9 — Agents pick the right kind
The docs your coding agent reads now say which kind to author for a task, not just what each kind is. An MCP server gets prompts and resources where they fit, instead of only tools. The guides also describe deploys to the Xano Engine correctly. Nothing changes at runtime.
npm install @xano/sdk@1.0.9Agents are told which kind fits each task
llms/object-kinds.md has a new "Choosing a kind" section. For each group of kinds that get confused, it says which one fits and why:
defineFunctionfor logic other code calls, aqueryfor HTTP, atoolfor AI callers.taskfor a timer, an asyncs.function.runfor work a request doesn't wait for,tableTriggerfor side effects of a row change (it fires on every write to the table).middlewarefor steps shared across many objects, anaddonfor related rows.agent(),mcpServer()orknowledge()depending on who runs the AI.s.realtime.publishfor server push.- A lambda only after native filters and expressions;
microserviceands.api.requestfor outside code. testsor aworkflowTest.
MCP servers get prompts and resources, not just tools
llms/kinds-agent-mcp.md now opens with who drives each MCP primitive. The model calls a tool(). The client app attaches a resource() by uri. The user picks a prompt() by name. Data the model has to fetch on its own mid-task stays a tool. The mcpServer() type docs say the same, and a prompt message's content is documented as accepting an MCP content block.
The deploy guides match the Xano Engine default
guides/cli.md and guides/deploying.md now say that a bare deploy goes to the Xano Engine, not a new ephemeral. They also say to cut releases from an ephemeral (deploy --ephemeral), because release create can't cut from the Engine.
v1.0.8 — Deploys stop overwriting Xano edits
A deploy to your workspace no longer overwrites edits a teammate made in Xano. This release also fixes a false preflight failure on zero-argument filters and warns when an agent run leaves its tools off.
npm install @xano/sdk@1.0.8deploy --to workspace refuses to overwrite edits made in Xano
Before writing, a deploy now reads the sync baseline that workspace diff uses. If an object it would overwrite was changed in Xano since your last deploy or pull, the deploy refuses with exit 2 and SDK_WORKSPACE_CHANGED. The objects are listed in details.objects, and an object changed on both sides is marked as a conflict. Run xanosdk pull workspace and commit, then deploy again, or pass --overwrite to deploy over the edits. --overwrite warns deploy.overwrite-changed and names what it replaced. --dry-run doesn't refuse: it lists the objects under changedInXano.
Only objects the deploy actually writes are checked. A merge leaves an object added in Xano alone, so that object only blocks a deploy under --prune or --replace. A branch with no baseline is never refused.
preflight no longer fails on zero-argument filters
A filter with no arguments, such as to_lower, read back from the engine as arg: []. That made preflight exit 2 on a workspace that was correct. An empty filter arg now compares equal to an absent one. The sync baseline's digest scheme moves to 2, so a baseline recorded by an older SDK is set aside and replaced on the next deploy or pull. It isn't read as every object having changed.
A warning when an agent run leaves its tools off
s.ai.agent.run on an agent that has tools, with allowToolExecution unset, now warns stack.agent-tools-off. Without the flag the agent can see its tools but never calls them, so it answers as if it had no data. Pass allowToolExecution: c.bool(true), or c.bool(false) if you want the tools off. Under --strict this warning fails the export until you set the flag.
Notes
--overwriteis refused on a deploy that refreshes an ephemeral or the Xano Engine, which keep no sync baseline.- The deploy guard reads the branch once, before the confirmation. An edit made in Xano between that read and the import isn't caught.
v1.0.7 — Your coding agent gets a backend
This release is about coding agents working on a Xano backend. An agent in a Xano project now reaches the Xano Engine on your machine over MCP: it can read tables and rows, seed data, and run functions and tests with nothing to configure by hand. xanosdk init adds a backend to an app you already have instead of refusing it, and the new xano-backend agent skill points agents there. The AGENTS.md that init writes now briefs an agent on a project with a backend. It also fixes .ts entries failing on Node 20 and 22 with tsx 4.23.
npm install @xano/sdk@1.0.7Coding agents reach the Xano Engine over MCP
Xano Engine v0.1.20 serves an MCP server, and xanosdk init connects Claude Code (.mcp.json) and Cursor (.cursor/mcp.json) to it. Through it an agent can look at the deployed backend (objects, table schemas, rows, run history), seed and edit rows, and run functions, tasks, triggers, endpoints and tests. Tables and code still change in xano/ and ship with xanosdk deploy.
The config holds no URL and no token. It launches xanosdk local mcp --stdio, which finds the running engine and its current bearer itself. It keeps working when the engine restarts on a new port, connects before the first deploy and lists the tools once one exists, and works in a fresh clone before npm install. A local deploy prints the MCP URL, and xanosdk local mcp prints the config for any other agent. An engine older than v0.1.20 says so on deploy, and xanosdk local update moves the project to one that serves MCP.
init adds a backend to an app you already have
In a non-empty directory, xanosdk init now writes xano/ and merges what the backend needs into the project, instead of refusing. That means the xano:* scripts and dependencies in package.json, a .gitignore block, and an AGENTS.md section. Your own entries win: an existing dependency keeps your range, and a xano:* script you defined differently is a clash. Every clash is listed and refused unless --force. Key order, indentation and line endings are kept. CommonJS hosts such as most Next.js apps work through a xano/package.json marker, so your manifest is untouched. A new project can now also skip the frontend with --framework none.
The xano-backend agent skill
npx @xano/sdk agent-skill install (or npx skills add xano-sdk/sdk, or /plugin marketplace add xano-sdk/sdk in Claude Code) installs a skill into Claude Code, Codex, Cursor, Copilot and Gemini CLI. It steers an agent asked to "add auth and a database" to a Xano backend inside the existing app. It stays out of projects that already have a backend, asks before installing Xano unasked, and hands off to AGENTS.md. The installer never overwrites a copy you edited, and uninstall removes only copies it wrote.
AGENTS.md is a backend brief, not a command list
The managed block init and init --from write is restructured into seven sections: Xano backend, Source of truth, Development workflow, Xano SDK, Backend changes, AI agent guidance, Troubleshooting. The env, testing, lock and add-on guidance keep their own headings.
The new sections cover:
- Xano is the backend, and no Node server is expected.
- Every file to inspect before building anything:
xano/index.ts,routes.gen.ts,xano.lock,xano/.env.example, thexanosdkblock inpackage.json, and.xano/. - The other backends (Express, Supabase, Prisma, …) that mean checking
xano/first. - Five common failures, each mapped to the project's own commands.
The brief also explains the engine's MCP server and where its job ends. xanosdk upgrade refreshes an existing project's block in place.
The brief's authoring example is compile-checked
The Xano SDK section shows one typed example: two tables, a pinned API group, and an authenticated POST with s.db.add. It lives in a type-checked fixture, and a test holds the brief to it verbatim, so the snippet an agent copies is one the compiler accepted.
.ts entries load again with tsx 4.23 on Node 20 and 22
A fresh scaffold resolves tsx to 4.23, whose CommonJS build of tsx/esm/api points at a file the package doesn't ship. Every command that loads xano/index.ts (xano:check, build, export, deploy) failed on Node 20 and 22 with Cannot find module …/tsx/dist/esm/api/esm/index.mjs. The CLI now loads tsx's ESM entry from your project, which works with any tsx version. Projects on 1.0.6 that hit this only need the upgrade.
Notes
- The MCP server needs Xano Engine v0.1.20 or later; older engines keep working without it.
- The rendered
AGENTS.mdis about 5.7k tokens in a React scaffold, up from about 3.6k. - Projects created before this release don't get the MCP configs written for them:
xanosdk local mcpprints the server block to paste into.mcp.jsonor.cursor/mcp.json, and a local deploy points at that command. CHANGELOG.mdis regenerated through 1.0.6.
v1.0.6 — Request types reach the frontend
This release types every request a frontend sends from routes.gen.ts alone, opens that file to marketplace modules so runtime validators can sit beside the types, and teaches workspace diff to say which side changed since the project and a workspace branch last matched. s.db.transaction no longer accepts as, which always bound null.
npm install @xano/sdk@1.0.6routes.gen.ts types every request the frontend sends
RouteInputs, ChannelInputs and MessageInputs now sit next to ROUTES, keyed the same way, so a renamed or retyped backend input breaks the frontend's build instead of failing at runtime. They are types only: the file still imports nothing. A dbLink input is typed as the linked table's columns, which is what a client actually sends.
import { ROUTES, routePath, type RouteInputs } from "../xano/routes.gen.js";
type NewPost = RouteInputs["POST posts"]; // { title: string; body?: string }Existing projects' committed routes.gen.ts gains the new type maps, so xano:check reports drift once, until the file is regenerated.
Toolchain modules add their own section to routes.gen.ts
A new routesManifest hook in @xano/sdk/plugin lets an installed module append a block to the file from a validator-neutral description of every route's inputs. It is synchronous and pure, may import only bare packages, and every writer (routes --emit, pull, generate, init, marketplace install|reinstall|remove) renders the same bytes. A module that fails keeps its previous block with a routes.module-failed warning, and --strict fails naming it. marketplace install and init --marketplace now also add a toolchain module's non-SDK peers (for example zod) as direct dependencies through the project's package manager.
workspace diff says which side changed since the last sync
deploy --to workspace, a verified promote, pull workspace and init --from workspace record a sync baseline per workspace branch in xano.lock under synced. workspace diff --json then reports changedThere (edited in Xano), changedHere (edited in this project), changedBoth (a conflict) and unclassified, with the same grouping in text output. A decoded table whose column the SDK compiles with default: "" and the instance stores as null no longer reports as differing right after init --from, and pull --no-secrets no longer rewrites xano/README.md for an unchanged backend.
⚠️ s.db.transaction no longer takes as
The engine's transaction statement returns nothing, so as always bound null while the docs said it bound the block's result. s.db.transaction now refuses as. Read the body's own variables instead; an s.return inside the body ends the whole stack. A pulled workspace that stores one still round-trips.
// before
s.db.transaction({ stack: [...], as: "result" })
// after
s.db.transaction({ stack: [s.db.add({ ..., as: "row" })] }) // then ref("row")A required input that carries a default is flagged
The engine drops a required input's default and refuses a request that omits it, so required: true plus default exported clean and then returned 400 for every request that left the input out. Export now warns field.input-required-default-ignored, naming nested object children by dotted path, and export --strict fails on it. Table columns and trigger inputs are left alone.
The scaffolded README keeps its platform section
Agents maintaining a scaffolded project rewrite the README to describe the app, and the passage saying what it is built on went with it. init and pull now write a ## Built with footer as a managed block that refreshAgentFiles restamps alongside AGENTS.md, and the opener leaves a visible "Describe here" slot. xanosdk upgrade refreshes both files.
Notes
Three runtime facts an agent had to guess at are now in the grounding docs: a db.transaction body shares the enclosing stack, an array.map transform's filter arguments can read $this paths and outer variables, and fl.add/fl.sub/fl.mul keep an int for int operands.
v1.0.5 — The Xano Engine is the default
This release makes the Xano Engine, the engine that runs on your machine, the default place your code goes. A bare xanosdk deploy now runs your backend locally with no Xano account, and --ephemeral sends it to Xano's cloud as the bare command used to. The engine is now called local everywhere in the CLI, and publish can put a frontend on it. deploy expecting an ephemeral, or that use the local-engine spellings, need the changes below.
npm install @xano/sdk@1.0.5⚠️ xanosdk deploy goes to the Xano Engine by default
With neither --ephemeral nor --to, deploy now runs your code on the Xano Engine on this machine. It needs no account and keeps rows across redeploys with --keep-data. Add --ephemeral to get the old behavior, a disposable ephemeral on Xano's cloud. --to workspace and --to tenant:<name> are unchanged. --ephemeral together with --local or --to is refused as two destinations, and --name / --expires-hours on a bare deploy now tell you to add --ephemeral. Every rerun hint that creates or refreshes an ephemeral now includes --ephemeral.
xanosdk deploy ./xano/index.ts # Xano Engine (default)
xanosdk deploy ./xano/index.ts --ephemeral # ephemeral on Xano's cloud (the old default)CI: a pipeline that runs a bare xanosdk deploy to get a preview URL must add --ephemeral.
⚠️ The engine is local in the CLI
The old spellings are refused, not aliased.
| Before (1.0.4) | Now |
|---|---|
deploy --local-engine[=<v|url|path>] |
deploy --local[=<v|url|path>] |
--to local-engine, local-engine:<name> |
--to local, local:<name> |
xanosdk local-engine list|token|stop|update|cache |
xanosdk local list|token|stop|update|cache |
--local (project-local ./.xano/auth.json) |
--local-auth |
XANOSDK_LOCAL_ENGINE_HOME, _OVERRIDE, _TOKEN |
XANOSDK_ENGINE_HOME, _OVERRIDE, _TOKEN |
package.json pin "localEngine": "vX.Y.Z" |
"engine": "vX.Y.Z" |
--json: "kind": "local-engine", localEngine key |
"kind": "local", engine key |
Warning codes local-engine.* |
local.* (e.g. local.import-failed) |
--local used to select the project-local credential file, so that flag is now --local-auth. An old localEngine pin is no longer read: the next deploy runs the latest engine and pins it under engine, so rename the key if you want to stay on your version. The engine cache stays at ~/.xanosdk/local-engine, so no engine needs downloading again.
xanosdk publish reaches the Xano Engine
xanosdk publish <dir> --to local (or local:<name>) uploads a built frontend to the engine's own static host, including a SvelteKit server half, without re-importing the backend. A bare publish after a local deploy goes there too. It uses the engine's own token, so no Xano credential is read and nothing prompts. --release and --branch are refused there. An engine too old to host static sites gets a message naming xanosdk local update.
⚠️ Scaffolded projects deploy locally first
In a project xanosdk init writes:
npm run xano:deploydeploys the backend to the Xano Engine with--keep-data.npm run xano:deploy:ephemeralbuilds the frontend and ships both to an ephemeral (the oldxano:deploy).xano:deploy:local-engineis removed.
The next steps init prints, the scaffolded README, AGENTS.md and .env.example follow the same order. Existing projects keep the scripts they have. Rename them by hand if you want the new layout.
The README and scaffolded README introduce Xano
The repository README now opens with Xano, the platform, and puts the Xano Engine first in the Quickstart, followed by ephemerals and then workspaces. Reference material moved into guides/, including a new Reading a compiled bundle guide. A scaffolded or pulled project's README now opens with a "Built on Xano" header and closes with links to the SDK guides and Xano's docs.
The SDK lives at github.com/xano-sdk/sdk
Package metadata, docs and scaffolded links now point at xano-sdk/sdk. It receives the source and notes for each release, and takes issues and security advisories.
Full changelog: v1.0.4...v1.0.5
v1.0.4 — Marketplace moves to its new catalogue
This patch release moves xanosdk marketplace to the catalogue's new home. The CLI now reads modules from a new default host, XANOSDK_MARKETPLACE_URL works with a tenant or ephemeral base, and a module withdrawn from the marketplace is refused by install again. No call-site changes are needed.
npm install @xano/sdk@1.0.4The marketplace reads from its new catalogue host
xanosdk marketplace list, search, details and install now read from https://xo2z-4vn5-mdxv.dev.xano.io by default. The routes are unchanged. Older CLI versions keep reading the previous host until you upgrade, or until you point them here with XANOSDK_MARKETPLACE_URL.
XANOSDK_MARKETPLACE_URL keeps the path on its base
An override such as https://<instance>/tenant/<name> used to lose its /tenant/<name> path, so a tenant or ephemeral catalogue was unreachable. The path is now kept and a trailing slash is ignored.
A module withdrawn from the marketplace is refused by install
A withdrawn module is now marked listed: false. Such a module drops out of list and search, and install refuses it. details still shows it, with a removed-from-the-marketplace warning on stderr. reinstall and remove still work on a project that already depends on it. --json output from details no longer carries a deleted field.
Full changelog: xanots/sdk@v1.0.3...v1.0.4
v1.0.3 — Agents and MCP servers pass preflight
This patch release fixes xanosdk preflight on workspaces that have agents or MCP servers, and makes pulling an existing workspace into code more reliable. Agents and MCP servers without sign-in no longer fail the round trip. Workspaces pulled with export/codegen now re-export as they were stored and the generated tree typechecks, including shapes older workspaces carry.
npm install @xano/sdk@1.0.3preflight no longer fails every agent and MCP server without oauth
An agent or MCP server with no oauth reads back from the instance with oauth: null, while the SDK leaves the key out. Preflight treated the two as different and failed with $.oauth: expected (absent), got null. They are now the same "no sign-in" state. A configured oauth block is still compared exactly.
UUID primary keys keep their stored default
A table with a uuid id stores default: "" on it, which the encoder dropped, so a pulled table failed to re-export as it was stored. The default is now kept.
Pulled workspaces decode more statements to typed code
Shapes that used to fall back to raw() now decode typed:
uncheckedAs: truefor a binding name the variable rule refusesAddonSpec.envelopefor an addon on the paging envelopebind: [{ expand: "<alias>.<column>", as }]for list-column expansion joins
Retired statements are reported as superseded rather than raw-fallback, and their bytes are carried through unchanged as before.
Guards the engine accepts are now warnings a def can allow
These were errors, so a pulled workspace that stored them could not compile:
- an addon binding a missing column
- a duplicate addon alias
- an unfit column default on a JSON-storage table (the new
table.column-default-unfit) - route shadowing
- loop control outside a loop
Each is now a warning that diagnostics.allow accepts. --strict still fails it without an allow. Test ids also accept the dashed UUID form.
Workspace defects are reported and the tree still compiles
Stored defects now come out as reported markers in code that still compiles: trim/children on columns that don't support them, a view filter with a blank operator (rawWhere()), stale call inputs and output columns ("key" as never), unparseable lambdas, and db statements missing a required input. lam.raw(..., { unchecked: true }) now also skips the module-syntax check.
Notes
The grounding files now cover expand, envelope and the pulled-tree markers, and the sandbox has a list-column expansion join example (ex_db_query_expand).
Full changelog: xanots/sdk@v1.0.2...v1.0.3
v1.0.2 — Fixtures can pin accepted hazards
This patch release lets a def deliberately author three shapes the engine accepts but 1.0 refused outright: an active cache with ttl: 0, a call passing an input its target does not declare, and a lambda body that does not parse. Each is still flagged by default, and export --strict still fails on it, but a fixture that pins the engine's behavior for that input can now say so.
npm install @xano/sdk@1.0.2cache.ttl of 0 is a warning a def can accept
An active cache whose ttl is not a positive whole number was an export error, so no def could author it, though the engine accepts it and simply never stores. It is now the warning cache.ttl-not-positive, accepted on a query or function with diagnostics: { allow: ["cache.ttl-not-positive"] }.
Passing an input the target does not declare is a warning a def can accept
The engine drops an undeclared input key without a word. statement.unknown-input (on s.function.run, s.api.call, s.middleware.call and the other *.call statements), test.unknown-input (a unit test's input) and db.addon-unknown-input (an attached addon's input) were errors; they are now warnings that the def's diagnostics.allow accepts. Without the allow, --strict still fails them, since a misspelt key is usually a bug.
lam.raw(code, { unchecked: true }) sends a body that does not parse
A body with a syntax error threw while the file loaded, so the engine's answer to one could not be tested. unchecked: true skips the parse check only, both in lam.raw and where the value lands in s.lambda or a fl.* filter. The binding, module-syntax and empty-body checks still apply.
s.lambda({ code: lam.raw("return (1 +;", { surface: "s.lambda", unchecked: true }), as: "result" })Notes
Development dependencies were updated to clear the open brace-expansion security advisories; nothing that ships in the package was affected.
v1.0.1 — Safer local-engine records
This patch release makes the local engine's record file safe under concurrent use and removes the SDK's handling of its retired package names. If you run several local-engine deploys or stops at once, they no longer undo each other's bookkeeping.
npm install @xano/sdk@1.0.1Concurrent local-engine deploys and stops no longer lose each other's records
Every write to the local-engine record file read the whole file, changed one entry and wrote it back with nothing serializing it, so two concurrent processes could drop a record, a completed-import marker, or bring back a stopped engine's record. All writes now go through one lock.
local-engine stop --all keeps the record of an engine a concurrent deploy just started
stop --all cleared every record left after its stops, so a deploy that recorded its engine after the listing lost that record: the engine was then treated as foreign and a later --keep-data deploy saw it as unfilled. It now clears only records that named no running engine, and only if they are unchanged.
The SDK no longer handles its retired package names
The install-time refusal of modules built for the old SDK packages, and the changelog generator's notes about the earlier version lines, are removed. The SDK is @xano/sdk.