In Inertia 3, what does createInertiaApp do, and how do its pages, resolve, setup and withApp options differ?
answer
- reads the page JSON from the root
- pages: './Pages' via the Vite plugin
- resolve(name, page) returns a component
- setup({ el, App, props }) mounts it
- withApp wraps providers; not with setup
basics
~20 screateInertiaApp 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 linesimport { 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
Know that createInertiaApp starts the client, finds the page component by its name and mounts it into the root element.
Explain where the initial page comes from, pages versus resolve, and when to use setup versus withApp.
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.
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