Svelte

Svelte 5 integration with Litestar Vite for lightweight, reactive applications.

Quick Start

litestar assets init --template svelte

This creates a Svelte 5 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"],
      resourceDir: "src",
    }),
  ],
})

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

# 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