React

React integration with Litestar Vite provides a modern development experience with Hot Module Replacement (HMR) and optimized production builds.

Quick Start

litestar assets init --template react

This creates a React 18+ project with TypeScript support.

Project Structure

React 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
├── tsconfig.json
└── src/
    ├── main.tsx        # React entry point
    ├── App.tsx         # Root component
    └── app.css

Backend Setup

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

examples/react/app.py
# VitePlugin with mode="spa" automatically:
# - Registers catch-all route for index.html
# - Generates typed route helpers (routes.ts) when types are enabled
vite = VitePlugin(
    config=ViteConfig(
        mode="spa",
        dev_mode=DEV_MODE,
        paths=PathConfig(root=here),
        types=TypeGenConfig(),  # generate_sdk=True is the default
        runtime=RuntimeConfig(port=5001),
    )
)

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 tailwindcss from "@tailwindcss/vite"
import react from "@vitejs/plugin-react"
import litestar from "litestar-vite-plugin"
import { defineConfig } from "vite"

export default defineConfig({
  plugins: [
    tailwindcss(),
    react(),
    litestar({
      input: ["src/main.tsx"],
      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>react</title>
  </head>
  <body>
    <div id="root"></div>
    <!-- Vite transforms this path based on the configured base -->
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

Note

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

React Component

import { useState, useEffect } from "react";

function App() {
  const [message, setMessage] = useState("");

  useEffect(() => {
    fetch("/api/summary")
      .then((res) => res.json())
      .then((data) => setMessage(data.headline));
  }, []);

  return (
    <div>
      <h1>React + Litestar</h1>
      <p>{message}</p>
    </div>
  );
}

export default App;

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