> ## Documentation Index
> Fetch the complete documentation index at: https://sdk.docs.xano.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Frontend hosting

> Serve a built frontend beside your backend on the Xano Engine or an ephemeral with --static, republish it alone with xanosdk publish, and render a SvelteKit app on the server on the Engine.

The Xano Engine and every ephemeral have a static host. `--static <dir>` on a deploy publishes a
built frontend there after the backend import, and `xanosdk publish` republishes one without
touching the backend.

## Publish with a deploy

Point `--static` at a directory your build already wrote:

```bash theme={null}
npm run build
npx xanosdk deploy ./xano/index.ts --static ./frontend/dist                # deploy to the Engine
npx xanosdk deploy ./xano/index.ts --ephemeral --static ./frontend/dist    # deploy to an ephemeral
```

`npm run xano:deploy:ephemeral` in a scaffolded project runs the second line for you.

The deploy reports the frontend's URL as `static.url`:

| Backend | Frontend URL |
| - | - |
| The Xano Engine | `http://<prefix>.localhost:<port>`. Chrome, Firefox and Safari 26 resolve `*.localhost` to your machine. |
| An ephemeral | Its own public URL on your instance, such as `https://a1b2c3-your-instance.xano.io`. |

Before archiving, the deploy writes the backend's URL into every HTML document in the build as
`window.XANO_HOST`, so the same build works on any backend with no rebuild. Read it at runtime with
a build-time fallback:

```ts theme={null}
const HOST = (typeof window !== "undefined" && window.XANO_HOST) || import.meta.env.VITE_XANO_HOST;
```

`--static-env KEY=VALUE` (repeatable) adds more public config as `window.<KEY>`. Everything
injected is served to the browser, so never put a secret there. [Typed frontend](/build/typed-frontend)
covers calling your APIs from the app.

A deploy with `--static` does not write `.env.local`: the frontend reads its backend URL at
runtime.

## Republish the frontend alone

`xanosdk publish <dir>` uploads a built directory and nothing else: no compile and no backend
import. With no `--to`, it publishes to the backend this project last deployed to.

```bash theme={null}
npm run xano:deploy:frontend                            # scaffolded project: build, then publish
npx xanosdk publish ./frontend/dist                      # to the last-deployed backend
npx xanosdk publish ./frontend/dist --to ephemeral       # to this project's ephemeral
npx xanosdk publish ./frontend/dist --to local           # to the Xano Engine
```

`--to` also takes `ephemeral:<name>`, `local:<name>`, `workspace` and `tenant:<name>`. Publishing to
a workspace or a tenant asks before it replaces what its users see (`--yes` in CI). Publishing to
the Engine includes a SvelteKit app's server half (below).

## How long a frontend URL lasts

A deploy that **replaces** the backend also clears its static hosting. A deploy without
`--keep-data` takes the published frontend down, and with `--static` publishes it again, possibly
at a new URL. The backend URL stays the same across the refresh.

To keep the frontend serving through a backend change, merge instead:

```bash theme={null}
npx xanosdk deploy ./xano/index.ts --ephemeral --keep-data
```

When an ephemeral expires, its backend and frontend go with it.

## Routing and size limits

The deploy infers whether the build is a single-page app or one document per route.
`--static-routing spa|multipage` overrides that, and is rarely needed.

| Host | Limit |
| - | - |
| An ephemeral | The compressed archive must be under 100 MB. |
| The Xano Engine | At most 20,000 files and 256 MB unpacked. Symbolic links are not uploaded. |

Both are checked before anything is uploaded, so an oversize build stops the run with nothing
written. An upload that fails after the backend landed leaves the backend in place, exits `3`,
and prints the `xanosdk publish` command that retries only the frontend.

## Server rendering with SvelteKit on the Engine

On the Xano Engine, a SvelteKit app can render on the server. Build it with the SDK's adapter,
which needs `esbuild` in the app:

```bash theme={null}
npm i -D esbuild
```

In a scaffolded SvelteKit project, SvelteKit's config is the object passed to `sveltekit()` in
`vite.config.ts`, and it already uses this adapter:

```ts theme={null}
// vite.config.ts, inside sveltekit({ ... })
import adapter from "@xano/sdk/sveltekit";
// ...
    adapter: adapter({ out: "frontend/dist" }),
```

The scaffold prerenders every route from `frontend/src/routes/+layout.ts`. Stop prerendering the
routes that should render per request. `vite build` then writes the client assets and prerendered
pages, a `404.html` fallback shell, and the server half in `.xano-ssr/`. Deploy it to the Engine:

```bash theme={null}
npx xanosdk deploy ./xano/index.ts --static ./frontend/dist
```

The Engine serves files as files and renders every other path (a dynamic route, `__data.json`, a
form action) through the server half. A server `load` reads the Engine's URL as `XANO_HOST`:

```js theme={null}
// src/routes/products/[slug]/+page.server.js
import { env } from "$env/dynamic/private";
export async function load({ params, fetch }) {
  const res = await fetch(`${env.XANO_HOST}/api:shop/products/${params.slug}`);
  return { product: await res.json() };
}
```

Know three things about the server half:

* **It can hold secrets.** SvelteKit inlines `$env/static/private` values into it, which is why
  the Engine never serves `/.xano-ssr/`.
* **It runs inside the Engine, not in Node.** Keep state in your API, since module state is per
  runtime. Bodies are buffered (no streaming), `request.formData()` reads urlencoded forms only,
  and there is no `AsyncLocalStorage`. A render has 30 seconds and may answer up to 10 MB.
* **Other hosts serve only the static half.** An ephemeral, a tenant or your workspace answers
  every non-file path with the `404.html` shell, which boots the app in the browser. Prerendered
  routes and routes with a universal `load` work there; a route whose data comes from
  `+page.server.js` does not.

## Next

* The backend your frontend calls: [The Xano Engine](/run/xano-engine) or
  [Ephemerals](/run/ephemerals).
* Putting a frontend in front of a release: [Promote and go live](/ship/promote-and-go-live).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.