skip to content

In Inertia 3, what does createInertiaApp do, and how do its pages, resolve, setup and withApp options differ?

level: middleimportance: should knowfreq 38%

answer

  1. reads the page JSON from the root
  2. pages: './Pages' via the Vite plugin
  3. resolve(name, page) returns a component
  4. setup({ el, App, props }) mounts it
  5. withApp wraps providers; not with setup

basics

~20 s

createInertiaApp reads the initial page object from the root element, resolves its component by name, and mounts or hydrates the adapter's App; pages or resolve decide how components load, setup takes over mounting, and withApp wraps the app in providers.

solid answer

~40 s

`createInertiaApp()` boots the client adapter (`@inertiajs/react`, `@inertiajs/vue3` or `@inertiajs/svelte`). It reads the page object from `<script data-page="app" type="application/json">`, resolves `page.component` to a module, and renders the adapter's `App`, hydrating when the root is marked server-rendered. With the `@inertiajs/vite` plugin a bare `createInertiaApp()` works: the plugin generates a resolver over `./pages` or `./Pages`, and `pages: './AppPages'` or `{ path, extension, lazy, transform }` customises it. Without the plugin you write `resolve(name, page)`, usually over `import.meta.glob`. `setup({ el, App, props })` replaces the default mounting, for example `createRoot(el).render(<App {...props} />)`, and switches off the plugin's automatic SSR entry. `withApp(app, { ssr, page })` is the lighter hook for wrapping providers or calling `app.use()`; it cannot be combined with `setup`. Other options include `layout`, `title`, `id`, `progress` and `defaults`.

code

jsx · 12 lines
jsx
import { createInertiaApp } from '@inertiajs/react'
import { PlayerProvider } from '@/player/PlayerProvider'
import AppLayout from '@/layouts/AppLayout'

createInertiaApp({
  pages: './pages',
  layout: () => AppLayout,
  title: (title) => (title ? `${title} - Tunes` : 'Tunes'),
  withApp(app) {
    return <PlayerProvider>{app}</PlayerProvider>
  },
})

go deeper

for a junior

Know that createInertiaApp starts the client, finds the page component by its name and mounts it into the root element.

for a middle

Explain where the initial page comes from, pages versus resolve, and when to use setup versus withApp.

for a senior

Configure the entry for real apps: providers via withApp, SSR-safe code paths using the ssr flag, default layouts, and what a custom setup does to automatic SSR.

for a principal

Set conventions for the client entry across a codebase, such as page directory naming, provider placement and upgrade paths between adapter majors.

## What createInertiaApp does `createInertiaApp` is the entry point of every **Inertia** client. It is exported by each adapter: `@inertiajs/react` (React 19), `@inertiajs/vue3` (Vue 3) and `@inertiajs/svelte` (Svelte 5, runes only). In the browser it: 1. finds the root element (id `app` unless you pass `id`); 2. reads the initial **page object** from the `<script data-page="app" type="application/json">` element the Laravel `@inertia` directive printed; 3. **resolves** `page.component`, such as `Albums/Show`, to a component module; 4. renders the adapter's `App` component, which owns the current page, layouts and head management; 5. hydrates instead of rendering from scratch when the root carries `data-server-rendered` from SSR; 6. starts the progress bar and applies `defaults` configuration. On the server, during SSR, the same call returns a render function the SSR server uses. ## Resolving pages: pages versus resolve | Option | Needs the Vite plugin | What you write | |---|---|---| | nothing | yes | a generated resolver over `./pages` and `./Pages` | | `pages: './AppPages'` | yes | a directory string | | `pages: { path, extension, lazy, transform }` | yes | directory, extensions, lazy loading (default `true`) and a name transform | | `resolve: (name, page) => ...` | no | your own lookup, usually with `import.meta.glob` | `resolve` receives the component name and, since Inertia 3, the full page object, so it can choose a component using page data. It may return the component, a module with a `default` export, or a promise of either. Laravel's Vite plugin also ships a `resolvePageComponent` helper in `laravel-vite-plugin/inertia-helpers` for this. ## Mounting: setup versus withApp **`setup({ el, App, props })`** hands you the root element, the `App` component and its props, and you mount it yourself: - React: `createRoot(el).render(<App {...props} />)` or `hydrateRoot(el, <App {...props} />)`; - Vue: `createApp({ render: () => h(App, props) }).use(plugin).mount(el)`. A custom `setup` also tells the Vite plugin not to generate SSR handling from this file, so SSR then needs its own entry. **`withApp(app, { ssr, page })`** is the Inertia 3 hook for customising without taking over mounting: - React receives the app element and returns a new element, for example wrapped in a context provider; - Vue receives the app instance, so you call `app.use()`, `app.provide()` or `app.component()`; - Svelte receives the context `Map` read by `getContext()`. The second argument says whether it runs during SSR and carries the page object, useful for initialising a locale from `page.props`. `setup` and `withApp` are **mutually exclusive**. ## Other options worth knowing - **`layout`**: a default persistent layout, or a function of the page name and page object returning one; - **`title`**: a callback `(title, page) => ...` that decorates every title set with `<Head>`, such as appending the app name; - **`id`**: the root element id, which must match the server's root view; - **`progress`**: progress bar settings, or `false`; - **`defaults`**: global defaults such as `form.recentlySuccessfulDuration` or `visitOptions`; - **`strictMode`** (React): wraps the app in `StrictMode`; - **`http`**: swap the built-in XHR client, for example for the Axios adapter. ## Inertia 3 changes to remember - the Vite plugin and the `pages` shorthand, so a bare `createInertiaApp()` is enough; - `withApp`, `layout` and `strictMode` options; - the page object as `resolve`'s second argument; - React 18 and Svelte 4 support dropped; ESM-only packages.

  • Why can setup and withApp not be combined?
    `withApp` wraps the element or app instance that the adapter builds during its own default mounting. A custom `setup` replaces that mounting, so there is nothing for `withApp` to wrap; you add providers inside `setup` yourself.
  • What does the title callback receive, and when does it run?
    It receives the title set through `<Head>` (or its `<title>` child) and, as a second argument, the current page object. Inertia calls it whenever a page sets a title, so one callback can append the app name everywhere.

saying these in an interview costs you the question

  • createInertiaApp fetches the first page's props with an extra XHR
  • The pages shorthand works without the @inertiajs/vite plugin
  • withApp and setup can be used together to add providers
  • Inertia 3's React adapter still supports React 18
  • resolve must return the component synchronously