# Inertia Django Documentation Extracted on: 2025-10-05T02:47:16.140Z Note: Code blocks are preserved and formatted for LLM consumption. ## guide/client-side-setup.md # Client-side setup ::: tip If you used the template based setup, you can skip client-side setup. It is already configured as part of the template based setup. ::: Once you have server-side configured, you then need to setup your client-side framework. Inertia currently provides support for React, Vue, and Svelte. ## Install dependencies First, install the Inertia client-side adapter corresponding to your framework of choice. ::: code-group shell [Vue] npm install @inertiajs/vue3 vue @vitejs/plugin-vue CODE BLOCK: shell [React] npm install @inertiajs/react react react-dom @vitejs/plugin-react CODE BLOCK: shell [Svelte 4, Svelte 5] npm install @inertiajs/svelte svelte @sveltejs/vite-plugin-svelte CODE BLOCK: ::: ## Configure Vite Create a vite.config.js file in your root directory and configure it for use with your frontend of choice and django-vite. ::: code-group js [Vue] // vite.config.js import { join, resolve } from "node:path"; import vue from "@vitejs/plugin-vue"; import { defineConfig, loadEnv } from "vite"; export default defineConfig((mode) => { const env = loadEnv(mode, process.cwd(), ""); const INPUT_DIR = "./frontend"; const OUTPUT_DIR = "./frontend/dist"; return { plugins: [vue()], resolve: { alias: { "@": resolve(INPUT_DIR), vue: "vue/dist/vue.esm-bundler.js", }, }, root: resolve(INPUT_DIR), base: "/static/", server: { host: "0.0.0.0", port: env.DJANGO_VITE_DEV_SERVER_PORT || 5173, watch: { usePolling: true, }, }, build: { manifest: "manifest.json", emptyOutDir: true, outDir: resolve(OUTPUT_DIR), rollupOptions: { input: { main: join(INPUT_DIR, "/js/main.js"), css: join(INPUT_DIR, "/css/main.css"), }, }, }, }; }); CODE BLOCK: js [React] // vite.config.js import { join, resolve } from "node:path"; import react from '@vitejs/plugin-react'; import { defineConfig, loadEnv } from "vite"; export default defineConfig((mode) => { const env = loadEnv(mode, process.cwd(), ""); const INPUT_DIR = "./frontend"; const OUTPUT_DIR = "./frontend/dist"; return { plugins: [react()], resolve: { alias: { "@": resolve(INPUT_DIR), }, }, root: resolve(INPUT_DIR), base: "/static/", server: { host: "0.0.0.0", port: env.DJANGO_VITE_DEV_SERVER_PORT || 5173, watch: { usePolling: true, }, }, build: { manifest: "manifest.json", emptyOutDir: true, outDir: resolve(OUTPUT_DIR), rollupOptions: { input: { main: join(INPUT_DIR, "/js/main.js"), css: join(INPUT_DIR, "/css/main.css"), }, }, }, }; }); CODE BLOCK: js [Svelte] // vite.config.js import { join, resolve } from "node:path"; import { svelte } from '@sveltejs/vite-plugin-svelte'; import { defineConfig, loadEnv } from "vite"; export default defineConfig((mode) => { const env = loadEnv(mode, process.cwd(), ""); const INPUT_DIR = "./frontend"; const OUTPUT_DIR = "./frontend/dist"; return { plugins: [svelte()], resolve: { alias: { "@": resolve(INPUT_DIR), }, }, root: resolve(INPUT_DIR), base: "/static/", server: { host: "0.0.0.0", port: env.DJANGO_VITE_DEV_SERVER_PORT || 5173, watch: { usePolling: true, }, }, build: { manifest: "manifest.json", emptyOutDir: true, outDir: resolve(OUTPUT_DIR), rollupOptions: { input: { main: join(INPUT_DIR, "/js/main.js"), css: join(INPUT_DIR, "/css/main.css"), }, }, }, }; }); CODE BLOCK: ::: ## Initialize the Inertia app Create a frontend directory in your root directory and add a js directory inside it. Inside the js directory, create a main.js file. Next, update your main JavaScript file (main.js) to boot your Inertia app. To accomplish this, we'll initialize the client-side framework with the base Inertia component. We will also configure CSRF to work properly with Django. ::: code-group js [Vue] // frontend/js/main.js import { createApp, h } from "vue"; import { createInertiaApp } from "@inertiajs/vue3"; import axios from "axios"; document.addEventListener("DOMContentLoaded", () => { axios.defaults.xsrfCookieName = "csrftoken"; axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"; createInertiaApp({ resolve: (name) => { const pages = import.meta.glob("../pages/**/*.vue", { eager: true }); return pages[../pages/${name}.vue]; }, setup({ el, App, props, plugin }) { createApp({ render: () => h(App, props) }) .use(plugin) .mount(el); }, }); }); CODE BLOCK: js [React] // frontend/js/main.js import { createInertiaApp } from "@inertiajs/react"; import { createElement } from "react"; import { createRoot } from "react-dom/client"; import axios from "axios"; document.addEventListener("DOMContentLoaded", () => { axios.defaults.xsrfCookieName = "csrftoken"; axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"; createInertiaApp({ resolve: (name) => { const pages = import.meta.glob("../pages/**/*.jsx", { eager: true }); return pages[../pages/${name}.jsx]; }, setup({ el, App, props }) { const root = createRoot(el); root.render(createElement(App, props)); }, }); }); CODE BLOCK: js [Svelte 4] // frontend/js/main.js import { createInertiaApp } from "@inertiajs/svelte"; import axios from "axios"; document.addEventListener("DOMContentLoaded", () => { axios.defaults.xsrfCookieName = "csrftoken"; axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"; createInertiaApp({ resolve: (name) => { const pages = import.meta.glob("../pages/**/*.svelte", { eager: true }); return pages[../pages/${name}.svelte]; }, setup({ el, App, props }) { new App({ target: el, props }); }, }); }); CODE BLOCK: js [Svelte 5] // frontend/js/main.js import { createInertiaApp } from "@inertiajs/svelte"; import { mount } from "svelte"; createInertiaApp({ resolve: (name) => { const pages = import.meta.glob("./Pages/**/*.svelte", { eager: true }); return pages[./Pages/${name}.svelte]; }, setup({ el, App, props }) { mount(App, { target: el, props }); }, }); CODE BLOCK: ::: The setup callback receives everything necessary to initialize the client-side framework, including the root Inertia App component. # Resolving components The resolve callback tells Inertia how to load a page component. It receives a page name (string), and returns a page component module. How you implement this callback depends on which bundler (Vite or Webpack) you're using. ::: code-group js [Vue] // frontend/js/main.js createInertiaApp({ resolve: (name) => { const pages = import.meta.glob("../pages/**/*.vue", { eager: true }); return pages[../pages/${name}.vue]; }, // ... }); CODE BLOCK: js [React] // frontend/js/main.js createInertiaApp({ resolve: (name) => { const pages = import.meta.glob("../pages/**/*.jsx", { eager: true }); return pages[../pages/${name}.jsx]; }, //... }); CODE BLOCK: js [Svelte 4, Svelte 5] // frontend/js/main.js createInertiaApp({ resolve: (name) => { const pages = import.meta.glob("../pages/**/*.svelte", { eager: true }); return pages[../pages/${name}.svelte]; }, //... }); CODE BLOCK: ::: By default we recommend eager loading your components, which will result in a single JavaScript bundle. However, if you'd like to lazy-load your components, see our code splitting documentation. ## Defining a root element By default, Inertia assumes that your application's root template has a root element with an id of app. This is already configured if you use the {% block inertia %} {% endblock %} template tag from inertia-django in your base html template. If your application's root element has a different id, you can provide it using the id property. js createInertiaApp({ id: "my-app", // ... }); --- ## guide/code-splitting.md # Code splitting Code splitting breaks apart the various pages of your application into smaller bundles, which are then loaded on demand when visiting new pages. This can significantly reduce the size of the initial JavaScript bundle loaded by the browser, improving the time to first render. While code splitting is helpful for very large projects, it does require extra requests when visiting new pages. Generally speaking, if you're able to use a single bundle, your app is going to feel snappier. To enable code splitting you'll need to tweak the resolve callback in your createInertiaApp() configuration, and how you do this is different depending on which bundler you're using. ## Using Vite Vite enables code splitting (or lazy-loading as they call it) by default when using their import.meta.glob() function, so simply omit the { eager: true } option, or set it to false, to disable eager loading. ::: code-group js [Vue] // frontend/entrypoints/inertia.js createInertiaApp({ resolve: (name) => { const pages = import.meta.glob("../pages/**/*.vue", { eager: true }); // [!code --] return pages[../pages/${name}.vue]; // [!code --] const pages = import.meta.glob("../pages/**/*.vue"); // [!code ++] return pages../pages/${name}.vue; // [!code ++] }, //... }); CODE BLOCK: js [React] // frontend/entrypoints/inertia.js createInertiaApp({ resolve: (name) => { const pages = import.meta.glob("../pages/**/*.jsx", { eager: true }); // [!code --] return pages[../pages/${name}.jsx]; // [!code --] const pages = import.meta.glob("../pages/**/*.jsx"); // [!code ++] return pages../pages/${name}.jsx; // [!code ++] }, //... }); CODE BLOCK: js [Svelte 4, Svelte 5] // frontend/entrypoints/inertia.js createInertiaApp({ resolve: (name) => { const pages = import.meta.glob("../pages/**/*.svelte", { eager: true }); // [!code --] return pages[../pages/${name}.svelte]; // [!code --] const pages = import.meta.glob("../pages/**/*.svelte"); // [!code ++] return pages../pages/${name}.svelte; // [!code ++] }, //... }); ::: --- ## guide/how-it-works.md # How it works With Inertia you build applications just like you've always done with your server-side web framework of choice. You use your framework's existing functionality for routing, controllers, middleware, authentication, authorization, data fetching, and more. However, Inertia replaces your application's view layer. Instead of using server-side rendering via Django templates, the views returned by your application are JavaScript page components. This allows you to build your entire frontend using React, Vue, or Svelte, while still enjoying the productivity of Django. As you might expect, simply creating your frontend in JavaScript doesn't give you a single-page application experience. If you were to click a link, your browser would make a full page visit, which would then cause your client-side framework to reboot on the subsequent page load. This is where Inertia changes everything. At its core, Inertia is essentially a client-side routing library. It allows you to make page visits without forcing a full page reload. This is done using the component, a light-weight wrapper around a normal anchor link. When you click an Inertia link, Inertia intercepts the click and makes the visit via XHR instead. You can even make these visits programmatically in JavaScript using router.visit(). When Inertia makes an XHR visit, the server detects that it's an Inertia visit and, instead of returning a full HTML response, it returns a JSON response with the JavaScript page component name and data (props). Inertia then dynamically swaps out the previous page component with the new page component and updates the browser's history state. **The end result is a silky smooth single-page experience. :tada:** To learn more about the nitty-gritty, technical details of how Inertia works under the hood, check out the protocol page. --- ## guide/index.md # Introduction Welcome to the documentation for inertia-django adapter for Django and Inertia.js. ## Why adapter-specific documentation? The official documentation for Inertia.js is great, but it's not Django-specific. This documentation aims to fill in the gaps and provide Django-specific examples and explanations. ## JavaScript apps the monolith way Inertia is a new approach to building classic server-driven web apps. We call it the modern monolith. Inertia allows you to create fully client-side rendered, single-page apps, without the complexity that comes with modern SPAs. It does this by leveraging existing server-side patterns that you already love. **Inertia has no client-side routing, nor does it require an API.** Simply write Django like you've always done! ### Not a framework Inertia isn't a framework, nor is it a replacement for your existing server-side or client-side frameworks. Rather, it's designed to work with them. Think of Inertia as glue that connects the two. Inertia does this via adapters. We currently have three official client-side adapters (React, Vue, and Svelte). ### Next steps Want to learn a bit more before diving in? Check out the who is it for and how it works pages. Or, if you're ready to get started, jump right into the installation instructions. --- ## guide/links.md # Links To create links to other pages within an Inertia app, you will typically use the Inertia component. This component is a light wrapper around a standard anchor link that intercepts click events and prevents full page reloads. This is how Inertia provides a single-page app experience once your application has been loaded. ## Creating links To create an Inertia link, use the Inertia component. Any attributes you provide to this component will be proxied to the underlying HTML tag. ::: code-group vue [Vue] import { Link } from "@inertiajs/vue3"; Home CODE BLOCK: jsx [React] import { Link } from "@inertiajs/react"; export default () => Home; CODE BLOCK: svelte [Svelte 4 , Svelte 5] import { inertia, Link } from '@inertiajs/svelte' Home Home CODE BLOCK: ::: ::: tip For Svelte, the use:inertia action can be applied to any HTML element. ::: By default, Inertia renders links as anchor elements. However, you can change the tag using the as prop. ::: code-group vue [Vue] import { Link } from "@inertiajs/vue3"; Logout CODE BLOCK: jsx [React] import { Link } from "@inertiajs/react"; export default () => ( Logout ); // Renders as... // Logout CODE BLOCK: svelte [Svelte 4 , Svelte 5] import { Link } from '@inertiajs/svelte' Logout CODE BLOCK: ::: ::: info Creating POST/PUT/PATCH/DELETE anchor links is discouraged as it causes "Open Link in New Tab / Window" accessibility issues. The component automatically renders a element when using these methods. ::: ## Method You can specify the HTTP request method for an Inertia link request using the method prop. The default method used by links is GET, but you can use the method prop to make POST, PUT, PATCH, and DELETE requests via links. ::: code-group vue [Vue] import { Link } from "@inertiajs/vue3"; Logout CODE BLOCK: jsx [React] import { Link } from "@inertiajs/react"; export default () => ( Logout ); CODE BLOCK: svelte [Svelte 4 , Svelte 5] import { inertia, Link } from '@inertiajs/svelte' Logout Logout CODE BLOCK: ::: ## Data When making POST or PUT requests, you may wish to add additional data to the request. You can accomplish this using the data prop. The provided data can be an object or FormData instance. ::: code-group vue [Vue] import { Link } from "@inertiajs/vue3"; Save CODE BLOCK: jsx [React] import { Link } from "@inertiajs/react"; export default () => ( Save ); CODE BLOCK: svelte [Svelte 4 , Svelte 5] import { inertia, Link } from '@inertiajs/svelte' Save Save CODE BLOCK: ::: ## Custom headers The headers prop allows you to add custom headers to an Inertia link. However, the headers Inertia uses internally to communicate its state to the server take priority and therefore cannot be overwritten. ::: code-group vue [Vue] import { Link } from "@inertiajs/vue3"; Save CODE BLOCK: jsx [React] import { Link } from "@inertiajs/react"; export default () => ( Save ); CODE BLOCK: svelte [Svelte 4 , Svelte 5] import { inertia, Link } from '@inertiajs/svelte' Save Save CODE BLOCK: ::: ## Browser history The replace prop allows you to specify the browser's history behavior. By default, page visits push (new) state (window.history.pushState) into the history; however, it's also possible to replace state (window.history.replaceState) by setting the replace prop to true. This will cause the visit to replace the current history state instead of adding a new history state to the stack. ::: code-group vue [Vue] import { Link } from "@inertiajs/vue3"; Home CODE BLOCK: jsx [React] import { Link } from "@inertiajs/react"; export default () => ( Home ); CODE BLOCK: svelte [Svelte 4 , Svelte 5] import { inertia, Link } from '@inertiajs/svelte' Home Home CODE BLOCK: ::: ## State preservation You can preserve a page component's local state using the preserveState prop. This will prevent a page component from fully re-rendering. The preserveState prop is especially helpful on pages that contain forms, since you can avoid manually repopulating input fields and can also maintain a focused input. ::: code-group vue [Vue] import { Link } from "@inertiajs/vue3"; Search CODE BLOCK: jsx [React] import { Link } from "@inertiajs/react"; export default () => ( Search ); CODE BLOCK: svelte [Svelte 4 , Svelte 5] import { inertia, Link } from '@inertiajs/svelte' Search Search CODE BLOCK: ::: ## Scroll preservation You can use the preserveScroll prop to prevent Inertia from automatically resetting the scroll position when making a page visit. ::: code-group vue [Vue] import { Link } from "@inertiajs/vue3"; Home CODE BLOCK: jsx [React] import { Link } from "@inertiajs/react"; export default () => ( Home ); CODE BLOCK: svelte [Svelte 4 , Svelte 5] import { inertia, Link } from '@inertiajs/svelte' Home Home CODE BLOCK: ::: For more information on managing scroll position, please consult the documentation on scroll management. ## Partial reloads The only prop allows you to specify that only a subset of a page's props (data) should be retrieved from the server on subsequent visits to that page. ::: code-group vue [Vue] import { Link } from "@inertiajs/vue3"; Show active CODE BLOCK: jsx [React] import { Link } from "@inertiajs/react"; export default () => ( Show active ); CODE BLOCK: svelte [Svelte 4 , Svelte 5] import { inertia, Link } from '@inertiajs/svelte' Show active Show active CODE BLOCK: ::: For more information on this topic, please consult the complete documentation on partial reloads. ## Active states It's often desirable to set an active state for navigation links based on the current page. This can be accomplished when using Inertia by inspecting the page object and doing string comparisons against the page.url and page.component properties. ::: code-group vue [Vue] import { Link } from "@inertiajs/vue3"; Users Users Users Users CODE BLOCK: jsx [React] import { usePage } from "@inertiajs/react"; export default () => { const { url, component } = usePage(); return ( // URL exact match... Users // Component exact match... Users // URL starts with (/users, /users/create, /users/1, etc.)... Users // Component starts with (Users/Index, Users/Create, Users/Show, etc.)... Users ); }; CODE BLOCK: svelte [Svelte 4 , Svelte 5] import { inertia, Link, page } from '@inertiajs/svelte' Users Users Users Users ::: You can perform exact match comparisons (===), startsWith() comparisons (useful for matching a subset of pages), or even more complex comparisons using regular expressions. Using this approach, you're not limited to just setting class names. You can use this technique to conditionally render any markup on active state, such as different link text or even an SVG icon that represents the link is active. ## Data loading attribute While a link is making an active request, a data-loading attribute is added to the link element. This allows you to style the link while it's in a loading state. The attribute is removed once the request is complete. --- ## guide/partial-reloads.md # Partial reloads Coming soon... --- ## guide/scroll-management.md # Scroll management ## Scroll resetting When navigating between pages, Inertia mimics default browser behavior by automatically resetting the scroll position of the document body (as well as any scroll regions you've defined) back to the top. In addition, Inertia keeps track of the scroll position of each page and automatically restores that scroll position as you navigate forward and back in history. ## Scroll preservation Sometimes it's desirable to prevent the default scroll resetting when making visits. You can disable this behaviour by setting the preserveScroll option to false. ::: code-group js [Vue] import { router } from "@inertiajs/vue3"; router.visit(url, { preserveScroll: false }); CODE BLOCK: js [React] import { router } from "@inertiajs/react"; router.visit(url, { preserveScroll: false }); CODE BLOCK: js [Svelte 4, Svelte 5] import { router } from "@inertiajs/svelte"; router.visit(url, { preserveScroll: false }); CODE BLOCK: ::: If you'd like to only preserve the scroll position if the response includes validation errors, set the preserveScroll option to "errors". ::: code-group js [Vue] import { router } from "@inertiajs/vue3"; router.visit(url, { preserveScroll: "errors" }); CODE BLOCK: js [React] import { router } from "@inertiajs/react"; router.visit(url, { preserveScroll: "errors" }); CODE BLOCK: js [Svelte 4, Svelte 5] import { router } from "@inertiajs/svelte"; router.visit(url, { preserveScroll: "errors" }); CODE BLOCK: ::: You can also lazily evaluate the preserveScroll option based on the response by providing a callback. ::: code-group js [Vue] import { router } from "@inertiajs/vue3"; router.post("/users", data, { preserveScroll: (page) => page.props.someProp === "value", }); CODE BLOCK: js [React] import { router } from "@inertiajs/react"; router.post("/users", data, { preserveScroll: (page) => page.props.someProp === "value", }); CODE BLOCK: js [Svelte 4, Svelte 5] import { router } from "@inertiajs/svelte"; router.post("/users", data, { preserveScroll: (page) => page.props.someProp === "value", }); CODE BLOCK: ::: When using an Inertia link, you can preserve the scroll position using the preserveScroll prop. ::: code-group vue [Vue] import { Link } from "@inertiajs/vue3"; Home CODE BLOCK: jsx [React] import { Link } from "@inertiajs/react"; export default () => ( Home ); CODE BLOCK: svelte [Svelte 4, Svelte 5] import { inertia, Link } from '@inertiajs/svelte' Home Home CODE BLOCK: ::: ## Scroll regions If your app doesn't use document body scrolling, but instead has scrollable elements (using the overflow CSS property), scroll resetting will not work. In these situations, you must tell Inertia which scrollable elements to manage by adding the scroll-region attribute to the element. html --- ## guide/server-side-setup.md # Server-side setup To get started with Inertia in Django, the first step is to configure Django to use the inertia-django server-side adapter. ::: tip For new projects, we recommend following the template based setup guide. ::: ## Template-based setup If you're starting a new project, we recommend configuring Django and Inertia using a django-vite-inertia template. This will require uv or pipx to be installed. First, let's create a new directory for our project. CODE BLOCK (shell): mkdir myproject Next, we'll use the template based installer. ::: code-group shell [uv] uvx copier copy gh:sarthakjariwala/django-vite-inertia myproject CODE BLOCK: shell [pipx] pipx run copier copy gh:sarthakjariwala/django-vite-inertia myproject CODE BLOCK: ::: This command will: - Create a new Django project in your myproject directory - Ask you to choose your preferred frontend framework: - React - Vue - Svelte - Ask you if you want to use Tailwind CSS - Ask you the database you want to use - SQLite - PostgreSQL - Ask you if you want to use Docker in development - Ask you if you want to use Docker in production - Set up Vite integration via django-vite - Set up Django to work with Inertia - Initialize the Inertia app - Configure CSRF to work properly with Django Example output: ? Your project name: todo ? Which database do you want to use? postgresql ? Which frontend do you want to use? vue ? Do you want to use Tailwind CSS? Yes ? Do you want to use Docker in development? Yes ? Do you want to use Docker in production? Yes CODE BLOCK: You're all set! You can now start your development server. ## Manual setup ::: tip Skip this section if you used the template based setup method. ::: ### Install dependencies Install the inertia-django server-side adapter and related dependencies. ::: code-group shell [uv] uv add inertia-django django-vite CODE BLOCK: shell [pip] python -m pip install inertia-django django-vite CODE BLOCK: ::: ### Update installed apps Add django_vite and inertia to your INSTALLED_APPS in settings.py. python INSTALLED_APPS = [ # ... "django_vite", "inertia", ] CODE BLOCK: ### Update middleware Next, add inertia.middleware.InertiaMiddleware to your MIDDLEWARE in settings.py. python MIDDLEWARE = [ # ... "inertia.middleware.InertiaMiddleware", ] CODE BLOCK: ### Configure settings Configure django-vite and inertia-django specific settings in settings.py. python # django-vite settings # If using HMR (hot module replacement) DJANGO_VITE = { "default": { "dev_mode": DEBUG, "dev_server_host": env.str("DJANGO_VITE_DEV_SERVER_HOST", default="localhost"), "dev_server_port": env.int("DJANGO_VITE_DEV_SERVER_PORT", default=5173), } } # Where ViteJS assets are built. DJANGO_VITE_ASSETS_PATH = BASE_DIR / "src" / "dist" # Include DJANGO_VITE_ASSETS_PATH into STATICFILES_DIRS to be copied inside # when run command python manage.py collectstatic STATICFILES_DIRS = [DJANGO_VITE_ASSETS_PATH] CODE BLOCK: > For a complete list of available vite related settings, see django-vite docs. python # inertia-django settings INERTIA_LAYOUT = "base.html" # update with your base template name CODE BLOCK: > For a complete list of available inertia-django settings, see readme. ### Update base template In your base html template, add the following: html {% load django_vite %} ... ... {% vite_hmr_client %} {% vite_asset 'js/main.js' %} {% block inertia %}{% endblock %} --- ## guide/the-protocol.md # The protocol This page contains a detailed specification of the Inertia protocol. Be sure to read the how it works page first for a high-level overview. ## HTML responses The very first request to an Inertia app is just a regular, full-page browser request, with no special Inertia headers or data. For these requests, the server returns a full HTML document. This HTML response includes the site assets (CSS, JavaScript) as well as a root in the page's body. The root serves as a mounting point for the client-side app, and includes a data-page attribute with a JSON encoded [page object] for the initial page. Inertia uses this information to boot your client-side framework and display the initial page component. CODE BLOCK (http): REQUEST GET: http://example.com/events/80 Accept: text/html, application/xhtml+xml RESPONSE HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 My app > [!NOTE] > While the initial response is HTML, Inertia does not server-side render the JavaScript page components. ## Inertia responses Once the Inertia app has been booted, all subsequent requests to the site are made via XHR with a X-Inertia header set to true. This header indicates that the request is being made by Inertia and isn't a standard full-page visit. When the server detects the X-Inertia header, instead of responding with a full HTML document, it returns a JSON response with an encoded [page object]. CODE BLOCK (http): REQUEST GET: http://example.com/events/80 Accept: text/html, application/xhtml+xml X-Requested-With: XMLHttpRequest X-Inertia: true X-Inertia-Version: 6b16b94d7c51cbe5b1fa42aac98241d5 RESPONSE HTTP/1.1 200 OK Content-Type: application/json Vary: X-Inertia X-Inertia: true { "component": "Event", "props": { "event": { "id": 80, "title": "Birthday party", "start_date": "2019-06-02", "description": "Come out and celebrate Jonathan's 36th birthday party!" } }, "url": "/events/80", "version": "c32b8e4965f418ad16eaebba1d4e960f", "encryptHistory": true, "clearHistory": false } ## The page object Inertia shares data between the server and client via a page object. This object includes the necessary information required to render the page component, update the browser's history state, and track the site's asset version. The page object includes the following four properties: 1. component: The name of the JavaScript page component. 2. props: The page props (data). 3. url: The page URL. 4. version: The current asset version. 5. encryptHistory: Whether or not to encrypt the current page's history state. 6. clearHistory: Whether or not to clear any encrypted history state. On standard full page visits, the page object is JSON encoded into the data-page attribute in the root . On Inertia visits, the page object is returned as the JSON payload. ## Asset versioning One common challenge with single-page apps is refreshing site assets when they've been changed. Inertia makes this easy by optionally tracking the current version of the site's assets. In the event that an asset changes, Inertia will automatically make a full-page visit instead of an XHR visit. The Inertia [page object] includes a version identifier. This version identifier is set server-side and can be a number, string, file hash, or any other value that represents the current "version" of your site's assets, as long as the value changes when the site's assets have been updated. Whenever an Inertia request is made, Inertia will include the current asset version in the X-Inertia-Version header. When the server receives the request, it compares the asset version provided in the X-Inertia-Version header with the current asset version. This is typically handled in the middleware layer of your server-side framework. If the asset versions are the same, the request simply continues as expected. However, if the asset versions are different, the server immediately returns a 409 Conflict response, and includes the URL in a X-Inertia-Location header. This header is necessary, since server-side redirects may have occurred. This tells Inertia what the final intended destination URL is. Note, 409 Conflict responses are only sent for GET requests, and not for POST/PUT/PATCH/DELETE requests. That said, they will be sent in the event that a GET redirect occurs after one of these requests. If "flash" session data exists when a 409 Conflict response occurs, Inertia's server-side framework adapters will automatically reflash this data. CODE BLOCK (http): REQUEST GET: http://example.com/events/80 Accept: text/html, application/xhtml+xml X-Requested-With: XMLHttpRequest X-Inertia: true X-Inertia-Version: 6b16b94d7c51cbe5b1fa42aac98241d5 RESPONSE 409: Conflict X-Inertia-Location: http://example.com/events/80 ## Partial reloads When making Inertia requests, the partial reload option allows you to request a subset of the props (data) from the server on subsequent visits to the same page component. This can be a helpful performance optimization if it's acceptable that some page data becomes stale. When a partial reload request is made, Inertia includes two additional headers with the request: X-Inertia-Partial-Data and X-Inertia-Partial-Component. The X-Inertia-Partial-Data header is a comma separated list of the desired props (data) keys that should be returned. The X-Inertia-Partial-Component header includes the name of the component that is being partially reloaded. This is necessary, since partial reloads only work for requests made to the same page component. If the final destination is different for some reason (eg. the user was logged out and is now on the login page), then no partial reloading will occur. CODE BLOCK (http): REQUEST GET: http://example.com/events Accept: text/html, application/xhtml+xml X-Requested-With: XMLHttpRequest X-Inertia: true X-Inertia-Version: 6b16b94d7c51cbe5b1fa42aac98241d5 X-Inertia-Partial-Data: events X-Inertia-Partial-Component: Events RESPONSE HTTP/1.1 200 OK Content-Type: application/json { "component": "Events", "props": { "auth": {...}, // NOT included "categories": [...], // NOT included "events": [...] // included }, "url": "/events/80", "version": "c32b8e4965f418ad16eaebba1d4e960f" } [page object]: #the-page-object --- ## guide/who-is-it-for.md # Who is Inertia.js for? Inertia was crafted for development teams and solo hackers who typically build server-side rendered applications using frameworks like Django, Ruby on Rails, or Laravel. You're used to creating controllers, retrieving data from the database (via an ORM), and rendering views. But what happens when you want to replace your server-side rendered views with a modern, JavaScript-based single-page application frontend? The answer is always "you need to build an API". Because that's how modern SPAs are built. This means building a REST or GraphQL API. It means figuring out authentication and authorization for that API. It means client-side state management. It means setting up a new Git repository. It means a more complicated deployment strategy. And this list goes on. It's a complete paradigm shift, and often a complete mess. We think there is a better way. **Inertia empowers you to build a modern, JavaScript-based single-page application without the tiresome complexity.** Inertia works just like a classic server-side rendered application. You create controllers, you get data from the database (via your ORM), and you render views. But, Inertia views are JavaScript page components written in React, Vue, or Svelte. This means you get all the power of a client-side application and modern SPA experience, but you don't need to build an API. We think it's a breath of fresh air that will supercharge your productivity. --- # CROSS-REFERENCE INDEX ## Authentication & Authorization - **guide/client-side-setup**: Key methods/components: - **guide/how-it-works**: Key methods/components: - **guide/links**: Key methods/components: - **guide/scroll-management**: Key methods/components: - **guide/server-side-setup**: Key methods/components: - **guide/the-protocol**: Key methods/components: - **guide/who-is-it-for**: Key methods/components: ## Forms & Validation - **guide/links**: Key methods/components: - **guide/scroll-management**: Key methods/components: - **guide/the-protocol**: Key methods/components: ## Routing & Navigation - **guide/how-it-works**: Key methods/components: - **guide/index**: Key methods/components: - **guide/links**: Key methods/components: - **guide/scroll-management**: Key methods/components: - **guide/the-protocol**: Key methods/components: ## Data Management - **guide/client-side-setup**: Key methods/components: - **guide/how-it-works**: Key methods/components: - **guide/links**: Key methods/components: - **guide/partial-reloads**: Key methods/components: - **guide/scroll-management**: Key methods/components: - **guide/the-protocol**: Key methods/components: ## File Handling ## Performance - **guide/code-splitting**: Key methods/components: ## Testing & Debugging ## Django Integration - **guide/how-it-works**: Key methods/components: - **guide/server-side-setup**: Key methods/components: - **guide/the-protocol**: Key methods/components: - **guide/who-is-it-for**: Key methods/components: # API REFERENCE