Library / SDK
inertiajs/inertia-django avatar
inertiajs/inertia-django

inertia-django is the Django side of the Inertia protocol, and nothing more

The Django adapter for Inertia.js

611 stars58 forksPythonMIT

At a glance

What is it?
inertia-django is the server adapter that lets a Django project return props instead of HTML templates, with its own prop serialisation rules, an optional-prop mechanism for partial reloads and a CSRF story that differs from Laravel's. It requires Django 5.2 and Python 3.10 or newer.
Who is it for?
Adopt inertia-django if your frontend is an Inertia client and your backend is Django, and you are prepared to write the page components in JavaScript rather than Django templates. Skip it if you want Django templates to stay in charge of rendering, or if you cannot move to Django 5.2 and Python 3.10, which the current package requires.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 68 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The adapter is a props transport, not a rendering layer

inertia-django is the Django adapter for the Inertia.js framework, and the smallness of the package is the point. It does not render your page. It returns a payload of props to a client that already knows how to turn props into components, and it handles the protocol details of the round trip so your Django views can stay ordinary views. Three ways of producing a response are offered, from the most to the least direct. The `render` function takes a request, a component name, a props dict and an optional template data dict. The `inertia` decorator covers the common case and lets a view return just the props dict. And the `InertiaResponse` class subclasses `HttpResponse`, so it accepts all of the arguments HttpResponse takes. The component name is a path relative to your pages directory without the extension, and the template data argument exists for variables your Django template needs, which the documentation notes is much less common. The audience is a team that has already decided Inertia is the right frontend shape and now needs the server half to behave.

Installing the app, the middleware and the layout

The backend install is a pip install, an entry in `INSTALLED_APPS`, an entry in `MIDDLEWARE`, and one template.

bash
pip install inertia-django
python
INSTALLED_APPS = [
  # django apps,
  'inertia',
  # your project's apps,
]
python
MIDDLEWARE = [
  # django middleware,
  'inertia.middleware.InertiaMiddleware',
  # your project's middleware,
]

The middleware is what makes the Inertia request headers meaningful on the Django side, and it has to sit in the right place in the stack, which is why the example shows it in the middle rather than at the end. The last piece is a layout template that exposes a `{% block inertia %}{% endblock %}` in the body, and the path to that layout becomes `INERTIA_LAYOUT` in your settings. The `render` function takes the request first, so the layout is the initial page that carries the app, and every subsequent navigation replaces its content in place rather than reloading the document.

Django does not serialise models to JSON for you

This is the part where Django differs from the Rails and Laravel adapters, and the documentation is explicit that it differs. Django does not convert objects to JSON by default, so inertia-django offers two ways to handle prop serialisation. The default is `InertiaJsonEncoder`, described as a barebones implementation that extends `DjangoJSONEncoder` with the ability to handle QuerySets and models. Models are encoded through Django's `model_to_dict` method, with the `password` field excluded. The documentation then names the limitation plainly: `model_to_dict` does not include fields where `editable=False`, such as automatic timestamps. That is a quiet trap. A model with `created_at` set by `auto_now_add` will not carry that field into the props unless you do something about it, and there is no error to tell you. The second mechanism, available since v1.2, is the `InertiaMeta` nested class.

python
class User(models.Model):
  name = models.CharField(max_length=255)
  password = models.CharField(max_length=255)
  created_at = models.DateField(auto_now_add=True)

  class InertiaMeta:
    fields = ('name', 'created_at')

Any class, not just a model, can carry an `InertiaMeta` class to say how it should be serialised, in the same spirit as Django Rest Framework's serializers. At present it only supports `fields`, and the documentation notes that this may be extended in future versions, so do not build a wider customisation surface on it yet.

Optional props and partial reloads avoid slow work on first paint

Inertia supports partial reloads, where the client asks the server for only the props it names. The Django adapter gives you a way to exploit that, and the reason to use it is performance on the first load. A prop wrapped in `optional` is not evaluated unless it is specifically requested by name in a partial reload, so a slow query does not run when the page first renders. The value is a callable, and the documentation shows the mechanism as a lambda.

python
from inertia import optional, inertia

@inertia('ExampleComponent')
def example(request):
  return {
    'name': lambda: 'Brandon', # this will be rendered on the first load as usual
    'data': optional(lambda: some_long_calculation()), # this will only be run when specifically requested by partial props and WILL NOT be included on the initial load
  }

Note that a plain lambda is also acceptable for the first-load case, which means you can defer evaluation of an expensive prop on the initial render as well. The companion function `always()` exists for data that must be included even when the client requests a different set of props, so you have a way to say which props are mandatory. The conceptual difference from the Rails and Laravel adapters is that Django does not serialise your props for you, so the lazy evaluation and the serialisation are two separate concerns you have to think about, and `optional` gives you the first one without touching the second.

Shared data through middleware and the CSRF name mismatch

Data that every component needs, such as information about the authenticated user, is handled by the `share` method, and the documentation suggests putting the call in custom middleware.

python
from inertia import share
from django.conf import settings
from .models import User

def inertia_share(get_response):
  def middleware(request):
    share(request,
      app_name=settings.APP_NAME,
      user_count=lambda: User.objects.count(), # evaluated lazily at render time
      user=lambda: request.user, # evaluated lazily at render time
    )

    return get_response(request)
  return middleware

The values are lambdas so that they are evaluated lazily at render time, which means a count query is not run on requests that never render a page. The CSRF story is where Django and Inertia v3 disagree, and the adapter resolves it. Django's CSRF tokens are tightly coupled with rendering templates, so Inertia Django automatically adds the CSRF cookie to every response, including the non-visit XHR requests made via the `useHttp` hook introduced in Inertia v3. The Inertia v3 HTTP client defaults to Laravel's `XSRF-TOKEN` cookie and `X-XSRF-TOKEN` header, while Django defaults to `csrftoken` and `X-CSRFToken`, so the client has to be told the Django names, or your project's custom names.

javascript
createInertiaApp({
  // ...
  http: {
    xsrfCookieName: 'csrftoken',
    xsrfHeaderName: 'X-CSRFToken',
  },
})

This is exactly the kind of small mismatch that costs an afternoon, and the documentation puts it in the install section for that reason.

External redirects use a 409 and a custom header

Sometimes an Inertia request has to leave the app entirely, or land on a non-Inertia endpoint inside it. The adapter provides a `location` method for a server-side initiated `window.location` visit.

python
from inertia import location

def external():
    return location("http://foobar.com/")

The mechanism is worth understanding because it explains the shape of the response. The call generates a `409 Conflict` response and includes the destination URL in the `X-Inertia-Location` header, and when the client receives that response Inertia automatically performs a `window.location = url` visit. A 409 is an unusual status to return deliberately, but here it is the signal that tells the JavaScript client this is not a page render and should be followed as a full document visit instead of a partial update. The alternative would be returning a 302 and having the client treat it as a normal redirect, which Inertia's protocol does not handle in the same way.

Version 2.0.0, a v3 upgrade guide, and a thin frontend story

The package sits at version 2.0.0, published on 2026-08-16, with the last push to the repository on the same date. That is a major version for a thin adapter, and the reason is the Inertia v3 protocol change rather than a redesign of the package itself. The README points to a v3 upgrade guide covering the required client, template, partial reload, flash, redirect and cache changes, and it is clearly not optional reading for anyone moving from an earlier version. The packaging is modern and strict. It requires Python 3.10 or newer and Django 5.2 or newer, and the classifiers list Django 5.2 and Django 6.1, so Django 4.x is out. The build uses `uv_build` as its backend, the module is named `inertia` with the module root at the top level, and the development tooling is strict too, with mypy in strict mode and the django-stubs plugin, pytest with pytest-django, and ruff. Server-side rendering is an optional extra rather than a core dependency, with `requests` pulled in only for the `ssr` extra. The one part of the documentation that is thin is the frontend, which is where the project is candid that Django specific frontend docs are coming soon, and where it recommends installing `django_vite` and following a separate example repository instead.

Editorial conclusion

Adopt inertia-django if your frontend is an Inertia client and your backend is Django, and you are prepared to write the page components in JavaScript rather than Django templates. Skip it if you want Django templates to stay in charge of rendering, or if you cannot move to Django 5.2 and Python 3.10, which the current package requires. Before you start, decide how your models serialise to JSON, because the default encoder silently omits fields marked editable=False, and read the v3 upgrade guide, since partial reloads, flash data and redirect behaviour all changed.

Frequently asked questions

How do I install the Inertia Django adapter?

Install `inertia-django` with pip, add `'inertia'` to `INSTALLED_APPS`, add `'inertia.middleware.InertiaMiddleware'` to `MIDDLEWARE`, then create a layout exposing `{% block inertia %}{% endblock %}` and set its path as `INERTIA_LAYOUT` in your settings.

How do I serialize a Django model to an Inertia prop?

By default `InertiaJsonEncoder` handles models and QuerySets through Django's `model_to_dict`, excluding the `password` field, but it omits fields with `editable=False` such as automatic timestamps. Add an `InertiaMeta` nested class with a `fields` tuple to control exactly what is serialized.

What does the optional() helper do in inertia-django?

It wraps a prop so it is not evaluated unless the client specifically requests it by name in a partial reload, which avoids running a slow calculation on the initial load. The `always()` helper is the counterpart for data that must always be included.

Which Django and Python versions does inertia-django 2.0.0 support?

The package metadata sets `requires-python = ">=3.10"` and depends on `django>=5.2`, with classifiers for Django 5.2 and Django 6.1. Server-side rendering is an optional extra that pulls in `requests`.

Official sources

  1. inertiajs/inertia-django on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/inertiajs-inertia-django.svg)](https://hysenlabs.com/projects/inertiajs-inertia-django)

Was this useful?