https://github.com/usecross/cross-inertia
Python support for Inertia.js
https://github.com/usecross/cross-inertia
django fastapi inertiajs python
Last synced: 5 days ago
JSON representation
Python support for Inertia.js
- Host: GitHub
- URL: https://github.com/usecross/cross-inertia
- Owner: usecross
- License: mit
- Created: 2025-11-02T21:00:39.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2026-05-31T10:46:05.000Z (29 days ago)
- Last Synced: 2026-06-22T18:34:20.481Z (7 days ago)
- Topics: django, fastapi, inertiajs, python
- Language: Python
- Homepage: https://cross-inertia.fastapicloud.dev/
- Size: 3.83 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 29
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Roadmap: ROADMAP.md
- Agents: AGENTS.md
Awesome Lists containing this project
README
# Inertia.js Adapter for Python Web Frameworks
[](https://github.com/patrick91/cross-inertia/actions/workflows/test.yml)
[](https://github.com/patrick91/cross-inertia/actions/workflows/lint.yml)
[](https://badge.fury.io/py/cross-inertia)
[](https://pypi.org/project/cross-inertia/)
[](https://opensource.org/licenses/MIT)
A Python adapter for using [Inertia.js](https://inertiajs.com/) with FastAPI and Django.
> [!CAUTION]
> This library is still in active development so it might not be fully stable yet.
**[π Documentation](https://inertia.patrick.wtf)** | **[π Quick Start](#quick-start)** | **[πΊοΈ Roadmap](./ROADMAP.md)**
## 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 (`props.errors`)
- β
History encryption for sensitive data
- β
External redirects (OAuth, payments, etc.)
- β
Partial reloads & shared data
- β
Merging props (infinite scroll support)
- β
View data (server-side template variables)
- β
TypeScript support
## Installation
```bash
# 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/`:
```bash
# 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
```python
from fastapi import FastAPI
from cross_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):
```python
from fastapi import FastAPI, Request, Depends
from cross_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 cross_web 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:
```typescript
// 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`):
```html
{{ vite()|safe }}
{{ page|safe }}
```
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)
When using `@inertiajs/react` 2.3+, enable the matching client-side bootstrap format:
```tsx
createInertiaApp({
defaults: {
future: {
useScriptElementForInitialPage: true,
},
},
// ...
});
```
### Using Custom Entry Points
```html
{{ vite()|safe }}
{{ vite('admin/app.js')|safe }}
```
**Backward compatibility**: The old `{{ vite_tags|safe }}` variable is still supported.
## Validation Errors
Validation errors are automatically handled:
```python
@app.post("/users")
async def create_user(inertia: InertiaDep):
errors = validate_user(request_data)
if errors:
# Returns 200 with props.errors 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:
```python
@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.
```python
# 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 (`props.errors`) | β
| β
| - |
| Asset versioning (basic) | β
| β
| - |
| **Asset version mismatch (409)** | β
| β
| - |
| **Partial reloads** | β
| β
| - |
| **Shared data** | β
| β
| - |
| **External redirects** | β
| β
| - |
| **History encryption** | β
| β
| - |
| **Merging props (infinite scroll)** | β
| β
| - |
| **View data** | β
| β
| - |
| Lazy props | β
| β³ Planned | π‘ Medium |
| Deferred props | β
| β³ Planned | π‘ Medium |
| Error bags | β
| β³ Planned | π’ Low |
| Prefetching | β
| β³ Planned | π’ Low |
| SSR | β
| β Not planned | - |
**See [ROADMAP.md](./ROADMAP.md) for detailed implementation plans and progress tracking.**
## Current Status
**Version:** v0.4.0 "Advanced Features"
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)
- β
Merging props (infinite scroll)
- β
View data (server-side template variables)
**Coming soon:**
- β³ Lazy props evaluation
- β³ Deferred props
## Contributing
Contributions are very welcome! This adapter aims to match the Laravel adapter's feature set.
**How to contribute:**
1. Check [GitHub Issues](https://github.com/patrick91/cross-inertia/issues) for open tasks
2. Pick a feature (look for `good first issue` or `high-priority` labels)
3. Read the linked Inertia.js documentation
4. Implement following existing patterns
5. Write tests and update documentation
6. Submit a PR!
**See [ROADMAP.md](./ROADMAP.md) for the full project roadmap and milestone planning.**
## License
MIT