Litestar-Vite Skill
Quick Reference
This skill covers SPA mode - a jinja-less configuration where:
- Backend serves API only (no template rendering)
- Frontend is a standalone React SPA
- TypeScript types/SDK auto-generated from OpenAPI schema
VitePlugin Setup (Python)
from litestar import Litestar
from litestar_vite import ViteConfig, VitePlugin, PathConfig, RuntimeConfig, TypeGenConfig
vite_config = ViteConfig(
mode="spa", # spa, template, htmx, hybrid, framework
dev_mode=True,
runtime=RuntimeConfig(
executor="bun", # or "npm", "pnpm"
port=5173,
host="localhost",
),
paths=PathConfig(
root=Path("src/js"),
bundle_dir=Path("src/js/dist"),
asset_url="/",
),
types=TypeGenConfig(
output=Path("src/js/src/lib/generated"),
openapi_path=Path("src/js/src/lib/generated/openapi.json"),
generate_zod=True, # Generate Zod validation schemas
generate_sdk=True, # Generate API client SDK
generate_routes=True, # Generate route definitions
),
)
app = Litestar(plugins=[VitePlugin(config=vite_config)])
Mode Selection
| Mode | Use Case |
|------|----------|
| spa | Single-page app (default proxy_mode=vite) |
| template | Server templates with Vite assets |
| htmx | HTMX partials with Vite assets |
| hybrid | Inertia or mixed rendering |
| framework | SSR frameworks (Nuxt, SvelteKit) |
Vite Frontend Config
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import litestar from 'litestar-vite-plugin'
export default defineConfig({
plugins: [
react(),
litestar({
input: ['src/main.tsx', 'src/styles.css'],
}),
],
})
Generated Files Structure
After running type generation:
src/js/src/lib/generated/
├── api/
│ ├── client/ # HTTP client utilities
│ ├── core/ # Core API utilities
│ ├── client.gen.ts # Client configuration
│ ├── index.ts # Main exports
│ ├── schemas.gen.ts # Serialization schemas
│ ├── sdk.gen.ts # API SDK functions
│ ├── types.gen.ts # TypeScript types
│ └── zod.gen.ts # Zod validation schemas
├── openapi.json # OpenAPI specification
├── routes.json # Route definitions (JSON)
└── routes.ts # Route definitions (TypeScript)
Using Generated API Client
Import SDK Functions
import {
accountLogin,
accountRegister,
listUsers,
createUser,
getUser,
updateUser,
deleteUser,
} from '@/lib/generated/api'
Import Types
import type {
User,
UserCreate,
UserUpdate,
AccountLogin,
Message,
} from '@/lib/generated/api'
Import Zod Schemas
import {
UserSchema,
UserCreateSchema,
AccountLoginSchema,
} from '@/lib/generated/api/zod.gen'
SDK with TanStack Query
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { listUsers, createUser } from '@/lib/generated/api'
import type { UserCreate } from '@/lib/generated/api'
export function useUsers() {
return useQuery({
queryKey: ['users'],
queryFn: async () => {
const response = await listUsers()
return response.data
},
})
}
export function useCreateUser() {
const queryClient = useQueryClient()
return useMutation({
mutationFn: async (data: UserCreate) => {
const response = await createUser({ body: data })
return response.data
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['users'] })
},
})
}
TanStack Form with Generated Zod
import { useForm } from '@tanstack/react-form'
import { zodValidator } from '@tanstack/zod-form-adapter'
import { UserCreateSchema } from '@/lib/generated/api/zod.gen'
import { createUser } from '@/lib/generated/api'
function CreateUserForm() {
const form = useForm({
defaultValues: { email: '', name: '' },
validatorAdapter: zodValidator(),
validators: { onChange: UserCreateSchema },
onSubmit: async ({ value }) => {
await createUser({ body: value })
},
})
// ... form JSX
}
CLI Commands
# Install frontend dependencies
litestar assets install
# Start Vite dev server
litestar assets serve
# Build for production
litestar assets build
# Generate TypeScript types from OpenAPI
litestar assets generate-types
# Export route metadata
litestar assets export-routes
# Check integration status
litestar assets status
# Diagnose issues
litestar assets doctor
TypeGenConfig Options
| Option | Default | Description |
|--------|---------|-------------|
| output | - | Output directory for generated files |
| openapi_path | - | Path for openapi.json |
| routes_path | - | Path for routes.json |
| routes_ts_path | - | Path for routes.ts |
| generate_zod | False | Generate Zod validation schemas |
| generate_sdk | False | Generate API client SDK |
| generate_routes | False | Generate route definitions |
| generate_page_props | False | Generate page props (for Inertia) |
| global_route | True | Export routes globally |
Adding New API Endpoints
- Create controller in
src/py/app/domain/{domain}/controllers/ - Create schemas in
src/py/app/domain/{domain}/schemas.py - Register controller in app routes
- Add schemas to
signature_namespace - Run
make types(orlitestar assets generate-types) - Use generated SDK in frontend
Troubleshooting
Types Not Updating
# Force regenerate
rm -rf src/js/src/lib/generated/*
make types
SDK Functions Missing
Ensure schemas are in signature_namespace:
# In server/core.py
app_config.signature_namespace.update({
**{k: getattr(schemas, k) for k in schemas.__all__},
})
Vite Dev Server Not Starting
Check VITE_DEV_MODE=true in .env and ensure:
- Node/Bun is installed
npm installhas been run in frontend directory
Official References
- https://litestar-org.github.io/litestar-vite/
- https://litestar-org.github.io/litestar-vite/usage/operation-modes/
- https://litestar-org.github.io/litestar-vite/usage/type-generation/
- https://litestar-org.github.io/litestar-vite/usage/migration-v015/
- https://github.com/litestar-org/litestar-vite/blob/main/src/py/litestar_vite/config/_types.py
- https://github.com/litestar-org/litestar-vite/blob/main/src/py/litestar_vite/config/_paths.py
Shared Styleguide Baseline
- Use shared styleguides for generic language/framework rules to reduce duplication in this skill.
- General Principles
- Litestar
- Python
- TypeScript
- Keep this skill focused on tool-specific workflows, edge cases, and integration details.
Scan to join WeChat group