Svelte#

Svelte integration with Litestar Vite for lightweight, reactive applications.

At a Glance#

  • Template: litestar assets init --template svelte

  • Mode: spa

  • Entry: src/main.ts

  • Dev: litestar run --reload (or litestar assets serve + litestar run)

Quick Start#

litestar assets init --template svelte

This creates a Svelte project with TypeScript support.

Project Structure#

Svelte applications use SPA mode - Vite serves the index.html directly:

my-app/
├── app.py              # Litestar backend (API only)
├── index.html          # Vite entry point (root level)
├── package.json
├── vite.config.ts
├── svelte.config.js
└── src/
    ├── main.ts         # Svelte entry point
    ├── App.svelte      # Root component
    └── style.css

Backend Setup#

In SPA mode, Litestar serves only your API endpoints. The VitePlugin handles serving the frontend automatically:

examples/svelte/app.py#
vite = VitePlugin(
    config=ViteConfig(
        mode="spa",
        dev_mode=DEV_MODE,
        paths=PathConfig(root=here),
        types=TypeGenConfig(),
        runtime=RuntimeConfig(port=5021),
    )
)

app = Litestar(route_handlers=[LibraryController], plugins=[vite], debug=True)

Key points:

  • mode="spa" tells Vite to serve index.html for non-API routes

  • No template_config needed - Jinja is not used in SPA mode

  • TypeGenConfig() enables TypeScript type generation from OpenAPI

Vite Configuration#

vite.config.ts#
import { svelte } from "@sveltejs/vite-plugin-svelte"
import tailwindcss from "@tailwindcss/vite"
import litestar from "litestar-vite-plugin"
import { defineConfig } from "vite"

export default defineConfig({
  plugins: [
    tailwindcss(),
    svelte(),
    litestar({
      input: ["src/main.ts"],
      types: "auto",
    }),
  ],
})

Key configuration:

  • input - Entry point(s) for your application

  • resourceDir - Source directory (explicitly set to src)

  • The plugin auto-reads assetUrl, bundleDir from .litestar.json (generated by Python)

HTML Entry Point#

In SPA mode, index.html lives at the project root and uses standard Vite syntax:

index.html#
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>svelte</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

Note

Unlike template mode, SPA mode doesn’t use Jinja helpers like {{ vite() }}. Vite processes the HTML directly.

Svelte Component#

<script lang="ts">
  import { onMount } from "svelte";

  let summary = $state<{ headline: string } | null>(null);

  onMount(async () => {
    const res = await fetch("/api/summary");
    summary = await res.json();
  });
</script>

<main>
  <h1>Svelte + Litestar</h1>
  {#if summary}
    <p>{summary.headline}</p>
  {/if}
</main>

Running#

Realtime streams#

Use createEventStreamStore() from litestar-vite-plugin/svelte for custom routes, or createQueueEventStreamStore() for Litestar Queues event envelopes. The readable store shares one connection across subscribers and disposes it after the last unsubscribe. See WebSocket and SSE event streams.

# Recommended: Litestar proxies Vite automatically in dev mode
litestar run --reload

# Alternative: Two-process setup
litestar assets serve  # Vite dev server
litestar run --reload  # Backend only (in another terminal)

Type Generation#

With types=TypeGenConfig() enabled, run:

litestar assets generate-types

This generates TypeScript types from your OpenAPI schema. See Type Generation for more details.

See Also#