---
title: SvelteKit
description: Run an eve agent and a SvelteKit app as one project with the eveSvelteKit Vite plugin.
url: "https://eve.dev/docs/guides/frontend/sveltekit"
docs_index: /llms.txt
---

> For an index of all documentation, see [/llms.txt](/llms.txt).

`eve/sveltekit` runs a SvelteKit frontend and an eve agent as one project. The `eveSvelteKit()` Vite plugin puts both on one dev server and one Vercel deploy. [`useEveAgent`](./use-eve-agent-svelte) finds the mounted routes on its own, so you configure no CORS or URL env vars.

## Prerequisites

- The `eve` package installed in your project (`npm install eve@latest`).
- An existing eve agent directory. If you don't have one, start from [Getting started](../../getting-started).
- A SvelteKit app to mount the agent in.

## Register the Vite plugin

Add `eveSvelteKit()` before `sveltekit()`:

```ts title="vite.config.ts"
import { sveltekit } from "@sveltejs/kit/vite";
import { eveSvelteKit } from "eve/sveltekit";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [eveSvelteKit(), sveltekit()],
});
```

The plugin looks for an `agent/` folder in the SvelteKit project root. Pass `eveRoot` when the agent lives elsewhere:

```ts
export default defineConfig({
  plugins: [
    eveSvelteKit({
      eveRoot: "../my-agent",
    }),
    sveltekit(),
  ],
});
```

The plugin accepts two options, `eveRoot` and `eveBuildCommand`.

## Call the binding

With the plugin registered, components call [`useEveAgent`](./use-eve-agent-svelte) from `eve/svelte` and don't pass `baseUrl`:

```svelte
<script lang="ts">
  import { useEveAgent } from "eve/svelte";

  const agent = useEveAgent();
  let message = $state("");
  let isBusy = $derived(agent.status === "busy");
  let isInputDisabled = $derived(isBusy || agent.status === "resuming");

  async function handleSubmit() {
    const text = message.trim();
    if (!text || isInputDisabled) return;
    message = "";
    await agent.send(text);
  }
</script>

<form onsubmit={(event) => {
  event.preventDefault();
  void handleSubmit();
}}>
  <input bind:value={message} disabled={isInputDisabled} />
  <button type="submit" disabled={isInputDisabled}>Send</button>
</form>
```

The browser still needs a production authentication policy. See [Authenticate browser requests](/docs/guides/frontend#authenticate-browser-requests) for the default policy, which rejects unverified requests, and for channel configuration.

## Dev vs deploy topology

- **Local dev.** `npm run dev` starts the eve dev server next to SvelteKit and proxies the eve routes to it. The browser talks only to the SvelteKit origin. `npm run build && npm run preview` works the same way: the preview server proxies the eve routes and reuses the shared eve server or starts one.

- **Vercel.** The SvelteKit app and the eve runtime deploy as a single project. On Vercel builds, the plugin adds an eve [service](https://vercel.com/docs/services) and routes `/eve/v1/**` to it before filesystem routing. The SvelteKit app serves everything else, and no `vercel.json` is required. By default, the generated service runs the installed eve binary from the SvelteKit app's dependencies, so the agent directory doesn't need its own `package.json`. When the agent needs its own build step, set `eveBuildCommand`:

  ```ts
  export default defineConfig({
    plugins: [
      eveSvelteKit({
        eveBuildCommand: "npm run build:eve",
      }),
      sveltekit(),
    ],
  });
  ```

- **Non-Vercel hosts.** When the eve service runs on a separate origin, pass `baseUrl` directly to `useEveAgent`:

  ```ts
  const agent = useEveAgent({
    baseUrl: "https://agent.example.com",
  });
  ```

## Managing vercel.json yourself

When `vercel.json` declares [`services`](https://vercel.com/docs/services), the plugin generates nothing, and your configuration controls routing. It must include the eve service (`framework: "eve"`) and a rewrite that sends `/eve/v1/*` requests to it, or the build fails:

```json title="vercel.json"
{
  "services": {
    "web": { "root": ".", "framework": "sveltekit" },
    "eve": { "root": "agent", "framework": "eve", "buildCommand": "eve build" }
  },
  "rewrites": [{ "source": "/eve/v1/(.*)", "destination": { "service": "eve" } }]
}
```

### Remove `experimentalServices`

Vercel doesn't route the `experimentalServices` field in `vercel.json`: both services build, but every `/eve/v1/*` request returns `NOT_FOUND`. The plugin ignores the field and warns that `vercel.json defines experimentalServices`. Remove it in one of two ways:

- **Generated (default).** Delete `vercel.json` (or its `experimentalServices` block) and set the project's Framework Preset to SvelteKit. The plugin generates the eve service and its routing on every Vercel build.
- **Hand-maintained.** Replace `experimentalServices` with the `services` and `rewrites` shown above, and keep the Services Framework Preset.

## What to read next

- [`useEveAgent` (Svelte)](./use-eve-agent-svelte): the binding API
- [Auth & route protection](../auth-and-route-protection)
- [Deployment](/docs/guides/deployment)

---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)