Vite
Vite is a fast frontend build tool that compiles JavaScript, CSS, and other assets for production. FastAPI Startkit ships with first-party Vite integration through ViteProvider, supporting HMR in development and manifest-based asset fingerprinting in production.
Example App
A fully working example is available in the vite-app directory of the monorepo. It demonstrates the complete setup: ViteProvider registration, config, Vite config, and a template using vite().
Setup
Install the optional vite package to use Vite integration:
pip install "fastapi-startkit[vite]"Then add ViteProvider to your application's providers list:
# bootstrap/application.py
from fastapi_startkit.vite import ViteProvider
app = Application(
base_path=...,
providers=[
ViteProvider,
...
],
)Publish the default config and asset files:
uv run python artisan provider:publish --provider=viteThis creates the following files in your project:
config/vite.py: FastAPI configuration for Vite.package.json: Vite dependencies and scripts.vite.config.js: Vite configuration with Tailwind CSS support.resources/js/app.ts: Main entry point.resources/css/app.css: Main CSS entry point.resources/templates/index.html: Example template using Vite.
After publishing, install the frontend dependencies and start the development server:
npm install
npm run devNOTE
Ensure APP_URL in your .env matches your FastAPI server URL (e.g., http://127.0.0.1:8000) so that Vite's Hot Module Replacement (HMR) can correctly communicate with the backend.
Configuration
config/vite.py uses a ViteConfig dataclass with these defaults:
from fastapi_startkit.vite import ViteConfig
config = ViteConfig(
public_path="public", # Root directory for assets
build_directory="build", # Subfolder inside public_path for production build
hot_file="hot", # Presence of this file signals dev server is running
manifest_filename="manifest.json",
asset_url="", # Optional CDN prefix for asset URLs
static_url="/build", # URL prefix used when mounting static files
mount_static=True, # Auto-mount public/build as a StaticFiles route
template=True, # Auto-bind Jinja2 templates (default)
templates_directory="resources/templates", # Directory the template engine reads from
)To use your custom configuration, pass the ViteConfig class when registering the provider. This is optional; if omitted, the provider will use the default settings.
from config.vite import ViteConfig
app = Application(
providers=[
(ViteProvider, ViteConfig),
],
)Loading a Page with JS and CSS
ViteProvider automatically sets up template rendering, so you can return an HTML page directly from a route. Resolve templates from the container and return a TemplateResponse:
from starlette.requests import Request
async def index(request: Request):
from fastapi_startkit import app
templates = app().make("templates")
return templates.TemplateResponse(request, "index.html", {"user": user})In your template, call vite() with the entry point to inject the JS and CSS tags:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>FastAPI + Vite</title>
{{ vite('resources/js/app.ts') }}
</head>
<body>
<h1>Hello from FastAPI + Vite</h1>
</body>
</html>vite(), vite_asset(), and vite_react_refresh() are all available as template globals — see Template Helpers below.
Development Mode (HMR)
Start the Vite dev server:
npm run devWhen the public/hot file exists, the Vite class switches to HMR mode automatically. Asset tags point to the HMR server (default: http://localhost:5173) instead of the build directory.
The hot file's content is the HMR origin URL. Vite writes it automatically; you can also create it manually:
http://localhost:5173Production Mode
Build your assets:
npm run buildVite writes public/build/manifest.json. The framework reads this manifest at startup (cached in memory) and generates hashed asset URLs with preload tags.
Template Helpers
With Jinja2 templates registered (via ViteProvider), three globals are available:
vite(entrypoint)
Generates <script type="module"> and <link rel="stylesheet"> tags plus <link rel="modulepreload"> preloads for the given entry point:
{# templates/index.html #}
{{ vite('resources/js/app.tsx') }}Multiple entry points:
{{ vite(['resources/js/app.tsx', 'resources/css/admin.css']) }}vite_asset(path)
Returns the public URL for a non-entry-point asset (images, fonts, etc.):
<img src="{{ vite_asset('resources/images/logo.png') }}">vite_react_refresh()
Injects the React Fast Refresh preamble. Required for React HMR. Must appear before vite():
{{ vite_react_refresh() }}
{{ vite('resources/js/app.tsx') }}In production mode, vite_react_refresh() returns an empty string — safe to always include.
CSP Nonce
vite = app.make("vite")
nonce = vite.use_csp_nonce() # generates a random nonce
# pass nonce to template context, set it in your CSP headerAll generated script and link tags will include the nonce attribute.
Custom Asset URL Resolver
Override how asset URLs are built (e.g., to add a CDN prefix dynamically):
vite = app.make("vite")
vite.create_asset_paths_using(lambda path: f"https://cdn.example.com/{path}")SRI Integrity
The manifest chunk key "integrity" is read by default and included as the integrity attribute on generated tags. Change the key or disable it:
vite.use_integrity_key("sri") # use a different key
vite.use_integrity_key(False) # disable integrity attributes