Skip to main content
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 <div> in the page’s body. The root <div> 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.
<html>
    <head>
        <title>My app</title>
        <link href="/css/app.css" rel="stylesheet">
        <script src="/js/app.js" defer></script>
    </head>
    <body>
        <div id="app" data-page='{"component":"Event","props":{"event":{"id":80,"title":"Birthday party","start_date":"2019-06-02","description":"Come out and celebrate Jonathan&apos;s 36th birthday party!"}},"url":"/events/80","version":"c32b8e4965f418ad16eaebba1d4e960f"}'></div>
    </body>
</html>
While the initial response is HTML, Inertia does not server-side render the JavaScript page components. For information on server-side rendering, see the SSR documentation.

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.
{
    "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": "6b16b94d7c51cbe5b1fa42aac98241d5",
    "encryptHistory": true,
    "clearHistory": false
}

Request Headers

The following headers are automatically sent by Inertia when making requests. You don’t need to set these manually, they’re handled by the Inertia client-side adapter.
X-Inertia
boolean
Set to true to indicate this is an Inertia request.
X-Requested-With
string
Set to XMLHttpRequest on all Inertia requests.
Accept
string
Set to text/html, application/xhtml+xml to indicate acceptable response types.
X-Inertia-Version
string
The current asset version to check for asset mismatches.
Purpose
string
Set to prefetch when making prefetch requests.
X-Inertia-Partial-Component
string
The component name for partial reloads.
X-Inertia-Partial-Data
string
Comma-separated list of props to include in partial reloads.
X-Inertia-Partial-Except
string
Comma-separated list of props to exclude from partial reloads.
X-Inertia-Reset
string
Comma-separated list of props to reset on navigation.
Cache-Control
string
Set to no-cache for reload requests to prevent serving stale content.
X-Inertia-Error-Bag
string
Specifies which error bag to use for validation errors.
X-Inertia-Infinite-Scroll-Merge-Intent
string
Indicates whether the requested data should be appended or prepended when using Infinite scroll.

Response Headers

The following headers should be sent by your server-side adapter in Inertia responses. If you’re using an official server-side adapter, these are handled automatically.
X-Inertia
boolean
Set to true to indicate this is an Inertia response.
X-Inertia-Location
string
Used for external redirects when a 409 Conflict response is returned due to asset version mismatches.
Vary
string
Set to X-Inertia to help browsers correctly differentiate between HTML and JSON responses.

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 can include the following properties:
component
string
The name of the JavaScript page component.
props
object
The page props (data).
url
string
The page URL.
version
string|number
The current asset version.
encryptHistory
boolean
clearHistory
boolean
Whether or not to clear any encrypted history state.
mergeProps
array
Array of prop keys that should be merged (appended) during navigation.
prependProps
array
Array of prop keys that should be prepended during navigation.
deepMergeProps
array
Array of prop keys that should be deep merged during navigation.
matchPropsOn
array
Array of prop keys to use for matching when merging props.
scrollProps
object
Configuration for infinite scroll prop merging behavior.
deferredProps
object
Configuration for client-side lazy loading of props.
On standard full page visits, the page object is JSON encoded into the data-page attribute in the root <div>. On Inertia visits (as indicated by the presence of the X-Inertia header), the page object is returned as the JSON payload.

Basic Page Object

A minimal page object contains the core properties.
{
    "component": "User/Edit",
    "props": {
        "user": {
            "name": "Jonathan"
        }
    },
    "url": "/user/123",
    "version": "6b16b94d7c51cbe5b1fa42aac98241d5",
    "clearHistory": false,
    "encryptHistory": false
}

Page Object with Deferred Props

When using deferred props, the page object includes a deferredProps configuration. Note that deferred props are not included in the initial props since they are loaded in a subsequent request.
{
    "component": "Posts/Index",
    "props": {
        "user": {
            "name": "Jonathan"
        }
    },
    "url": "/posts",
    "version": "6b16b94d7c51cbe5b1fa42aac98241d5",
    "clearHistory": false,
    "encryptHistory": false,
    "deferredProps": {
        "default": [
            "comments",
            "analytics"
        ],
        "sidebar": [
            "relatedPosts"
        ]
    }
}

Page Object with Merge Props

When using merge props, additional configuration is included.
{
    "component": "Feed/Index",
    "props": {
        "user": {
            "name": "Jonathan"
        },
        "posts": [
            {
                "id": 1,
                "title": "First Post"
            }
        ],
        "notifications": [
            {
                "id": 2,
                "message": "New comment"
            }
        ],
        "conversations": {
            "data": [
                {
                    "id": 1,
                    "title": "Support Chat",
                    "participants": [
                        "John",
                        "Jane"
                    ]
                }
            ]
        }
    },
    "url": "/feed",
    "version": "6b16b94d7c51cbe5b1fa42aac98241d5",
    "clearHistory": false,
    "encryptHistory": false,
    "mergeProps": [
        "posts"
    ],
    "prependProps": [
        "notifications"
    ],
    "deepMergeProps": [
        "conversations"
    ],
    "matchPropsOn": [
        "posts.id",
        "notifications.id",
        "conversations.data.id"
    ]
}

Page Object with Scroll Props

When using Infinite scroll, the page object includes a scrollPropsconfiguration.
{
    "component": "Posts/Index",
    "props": {
        "posts": {
            "data": [
                {
                    "id": 1,
                    "title": "First Post"
                },
                {
                    "id": 2,
                    "title": "Second Post"
                }
            ]
        }
    },
    "url": "/posts?page=1",
    "version": "6b16b94d7c51cbe5b1fa42aac98241d5",
    "clearHistory": false,
    "encryptHistory": false,
    "mergeProps": [
        "posts.data"
    ],
    "scrollProps": {
        "posts": {
            "pageName": "page",
            "previousPage": null,
            "nextPage": 2,
            "currentPage": 1
        }
    }
}

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 GETredirect occurs after one of these requests.
When the Inertia client receives a 409 Conflict response, it checks for the presence of the X-Inertia-Location header. If this header exists, Inertia performs a full-page visit to the URL specified in the header. This ensures that the user always has the latest assets loaded. If “flash” session data exists when a 409 Conflict response occurs, Inertia’s server-side framework adapters will automatically reflash this data. You can read more about this on the asset versioning page.

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. See the partial reloads documentation for details. 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.
{
    "component": "Events",
    "props": {
        "auth": {...},
        // NOT included
        "categories": [...], // NOT included
        "events": [...]      // included
    },
    "url": "/events/80",
    "version": "6b16b94d7c51cbe5b1fa42aac98241d5"
}

HTTP Status Codes

Inertia uses specific HTTP status codes to handle different scenarios.
Status CodeDescription
200 OKStandard successful response for both HTML and Inertia JSON responses.
302 FoundStandard redirect response. Inertia’s server-side adapters automatically convert this to 303 See Other when returned after PUT, PATCH, or DELETE requests.
303 See OtherUsed for redirects after non-GET requests. This status code tells the browser to make a GET request to the redirect URL, preventing duplicate form submissions that could occur if the browser repeated the original request method.
409 ConflictReturned when there’s an asset version mismatch or for external redirects. For asset mismatches, this prompts a full page reload. For external redirects, the response includes an X-Inertia-Location header and triggers a window.location redirect client-side.