Inertia.js adapter for Python web frameworks
Project description
Inertia.js FastAPI Adapter
A Python adapter for using Inertia.js with FastAPI.
📚 Documentation | 🚀 Quick Start | 🗺️ Roadmap
Features
- ✅ Full Inertia.js protocol support
- ✅ Vite integration (dev & production)
- ✅ Auto-detection of Vite entry point from vite.config.ts/js
- ✅ Asset versioning for cache busting
- ✅ Validation error handling (422 responses)
- ✅ History encryption for sensitive data
- ✅ External redirects (OAuth, payments, etc.)
- ✅ Partial reloads & shared data
- ✅ TypeScript support
Installation
# Install from PyPI using uv (recommended)
uv pip install cross-inertia
# Or using pip
pip install cross-inertia
# Or install from source
uv pip install -e .
Try the Demo
We have a full-featured cat adoption demo app in examples/fastapi/:
# Using just (recommended)
just demo-install # Install dependencies
just demo-fastapi # Run the demo
# Or manually
cd examples/fastapi
bun install
./run-dev.sh
Visit http://127.0.0.1:8000 to see Inertia.js + FastAPI in action!
Quick Start
1. Basic Setup
from fastapi import FastAPI
from inertia.fastapi import InertiaDep
app = FastAPI()
@app.get("/")
async def home(inertia: InertiaDep):
return inertia.render(
"Home",
{
"message": "Hello from Inertia!"
}
)
2. Custom Configuration
If you need to customize the Inertia configuration (e.g., different template directory or Vite settings):
from fastapi import FastAPI, Request, Depends
from inertia.fastapi import InertiaResponse, Inertia
# Create custom InertiaResponse instance
inertia_response = InertiaResponse(
template_dir="my_templates",
vite_dev_url="http://localhost:5173",
manifest_path="dist/.vite/manifest.json",
vite_entry="src/main.tsx", # Optional: auto-detected from vite.config
vite_config_path="vite.config.ts" # Optional: defaults to vite.config.ts
)
app = FastAPI()
def get_custom_inertia(request: Request) -> Inertia:
from lia import StarletteRequestAdapter
adapter = StarletteRequestAdapter(request)
return Inertia(request, adapter, inertia_response)
@app.get("/")
async def home(inertia: Inertia = Depends(get_custom_inertia)):
return inertia.render("Home", {"message": "Hello!"})
Configuration Options
InertiaResponse Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
template_dir |
str |
"templates" |
Directory containing your root HTML template |
vite_dev_url |
str |
"http://localhost:5173" |
Vite dev server URL |
manifest_path |
str |
"static/build/.vite/manifest.json" |
Path to Vite manifest file (production) |
vite_entry |
str | None |
None |
Vite entry point (auto-detected from config if None) |
vite_config_path |
str |
"vite.config.ts" |
Path to vite.config.ts/js for auto-detection |
Auto-Detection of Vite Entry
By default, the adapter will attempt to read your vite.config.ts (or .js) file and extract the entry point from:
// vite.config.ts
export default defineConfig({
build: {
rollupOptions: {
input: "frontend/app.tsx", // ← Auto-detected
},
},
});
This means you don't need to specify vite_entry manually - it will match your Vite configuration automatically!
Root Template
Create a template file (default: templates/app.html):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{ vite()|safe }}
</head>
<body>
<div id="app" data-page='{{ page }}'></div>
</body>
</html>
The {{ vite() }} function will automatically include:
- React Fast Refresh scripts (dev mode)
- Vite client scripts (dev mode)
- Your entry point script
- Built CSS and JS files (production mode)
Using Custom Entry Points
<!-- Use default entry (from config/auto-detection) -->
{{ vite()|safe }}
<!-- Use custom entry point -->
{{ vite('admin/app.js')|safe }}
Backward compatibility: The old {{ vite_tags|safe }} variable is still supported.
Validation Errors
Validation errors are automatically handled:
@app.post("/users")
async def create_user(inertia: InertiaDep):
errors = validate_user(request_data)
if errors:
# Returns 422 status for Inertia requests
return inertia.render(
"Users/Create",
{"user": request_data},
errors=errors
)
# Create user...
return inertia.render("Users/Show", {"user": new_user})
External Redirects
Use inertia.location() to redirect to external websites or non-Inertia pages:
@app.get("/auth/github")
async def github_oauth(inertia: InertiaDep):
"""Redirect to GitHub OAuth"""
oauth_url = f"https://github.com/login/oauth/authorize?client_id={CLIENT_ID}"
return inertia.location(oauth_url)
@app.get("/shelter/{id}/directions")
async def get_directions(id: int, inertia: InertiaDep):
"""Redirect to Google Maps"""
shelter = get_shelter(id)
maps_url = f"https://maps.google.com/?q={shelter.address}"
return inertia.location(maps_url)
This returns a 409 Conflict response with X-Inertia-Location header, which the client automatically follows with a full page navigation.
History Encryption
Protect sensitive data in browser history by encrypting page state. This prevents users from viewing sensitive information after logging out by pressing the back button.
# Encrypt sensitive pages
@app.get("/account/transactions")
async def transactions(inertia: InertiaDep):
inertia.encrypt_history() # Enable encryption
return inertia.render("Transactions", {
"balance": user.balance,
"transactions": user.get_transactions()
})
# Clear encrypted history on logout
@app.post("/logout")
async def logout(inertia: InertiaDep):
clear_user_session()
inertia.clear_history() # Rotate encryption keys
return inertia.render("Login", {})
How it works:
- Uses browser's Web Crypto API (AES-GCM encryption)
- Encryption keys stored in sessionStorage
clear_history()rotates keys, making old history unreadable- Only works over HTTPS (except localhost)
Use cases: Banking apps, healthcare (HIPAA), admin panels, any sensitive data
Development vs Production
The adapter automatically detects whether Vite dev server is running:
- Dev mode: Includes Vite dev server scripts and React Fast Refresh
- Production mode: Reads from manifest.json and includes built assets
No configuration changes needed - it just works!
Feature Status
| Feature | Laravel Inertia | FastAPI Inertia | Priority |
|---|---|---|---|
| Basic protocol | ✅ | ✅ | - |
Template function {{ vite() }} |
✅ @vite |
✅ | - |
| Auto Vite entry detection | ✅ | ✅ | - |
| Dev/Prod mode detection | ✅ | ✅ | - |
| Validation errors (422) | ✅ | ✅ | - |
| Asset versioning (basic) | ✅ | ✅ | - |
| Asset version mismatch (409) | ✅ | ✅ | - |
| Partial reloads | ✅ | ✅ | - |
| Shared data | ✅ | ✅ | - |
| External redirects | ✅ | ✅ | - |
| History encryption | ✅ | ✅ | - |
| Lazy props | ✅ | ⏳ Planned | 🟡 Medium |
| Deferred props | ✅ | ⏳ Planned | 🟡 Medium |
| Merging props | ✅ | ⏳ Planned | 🟡 Medium |
| Error bags | ✅ | ⏳ Planned | 🟢 Low |
| Prefetching | ✅ | ⏳ Planned | 🟢 Low |
| SSR | ✅ | ❌ Not planned | - |
See ROADMAP.md for detailed implementation plans and progress tracking.
Current Status
Version: v0.2.0 "Production Ready"
This adapter implements all production-critical Inertia features and is ready for production use.
Production-ready features:
- ✅ Basic page rendering
- ✅ Form submissions with validation
- ✅ Navigation between pages
- ✅ Development with Vite HMR
- ✅ Asset version mismatch handling (409 Conflict)
- ✅ Partial reloads for performance
- ✅ Shared data (auth, flash messages)
- ✅ External redirects (OAuth, payments)
- ✅ History encryption (sensitive data protection)
Coming soon:
- ⏳ Lazy props evaluation
- ⏳ Deferred props
- ⏳ Merging props (infinite scroll)
Contributing
Contributions are very welcome! This adapter aims to match the Laravel adapter's feature set.
How to contribute:
- Check GitHub Issues for open tasks
- Pick a feature (look for
good first issueorhigh-prioritylabels) - Read the linked Inertia.js documentation
- Implement following existing patterns
- Write tests and update documentation
- Submit a PR!
See ROADMAP.md for the full project roadmap and milestone planning.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cross_inertia-0.3.0.tar.gz.
File metadata
- Download URL: cross_inertia-0.3.0.tar.gz
- Upload date:
- Size: 2.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b60f859db5bcd059774e3d039c6c5d909d58f0ad794b5ba5d933ce53d4dc6074
|
|
| MD5 |
61bd7eaf2222425ca5b91d5aef19dcda
|
|
| BLAKE2b-256 |
2778f044d0166cb5016275288aa943995d79c6085a18d7e78edef3f8c62169e3
|
File details
Details for the file cross_inertia-0.3.0-py3-none-any.whl.
File metadata
- Download URL: cross_inertia-0.3.0-py3-none-any.whl
- Upload date:
- Size: 13.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0e19507a2339d60771f2c9d6593029dc4d65926e6d910fabaa5a20435f071f6
|
|
| MD5 |
334da6db0b377c2497e7da8a962c5590
|
|
| BLAKE2b-256 |
a70cdeecd4e2c93a940a1acd75ad1f0f1c96497125777b4cd08a7ef1996589b2
|