@samveys/inertia

Version
1.0.2Nov 5, 2026
Install
pnpm add @samveys/inertia

From packages/inertia/README.md in the framework repository.

The Inertia protocol v2 for Samveys. No runtime dependencies; use it with the official Inertia client (Vue, React or Svelte).

Set up

ts
import { http } from '@samveys/http'
import { inertia } from '@samveys/inertia'
import { template } from '@samveys/template'
import { view } from '@samveys/view'
import { vite } from '@samveys/vite'

export const plugins = [
  http(),
  view(),
  template(),
  vite(),
  inertia({
    rootView: 'app',
    share: (ctx) => ({ path: ctx.url.pathname }),
  }),
]

The root view is a template that prints the page element:

html
{{-- resources/views/app.tpl.html --}}
<!doctype html>
<html>
  <head>@inertiaHead @vite('resources/app.ts')</head>
  <body>@inertia</body>
</html>

@inertia prints <div id="app" data-page="{escaped JSON}">.

Render a page

ts
import { defer, optional } from '@samveys/inertia'
import type { Router } from '@samveys/http'

export function routes(router: Router): void {
  router.get('/users', (ctx) =>
    ctx.inertia.render('Users/Index', {
      users: () => [{ id: 1, name: 'Ann' }],
      roles: optional(() => ['admin']),
      stats: defer(() => ({ total: 1 }), 'sidebar'),
    }),
  )
  router.put('/users/:id', (ctx) => ctx.inertia.redirect('/users'))
}
RequestResponse
Browser visitHTML: the root view with data-page
X-Inertia: trueJSON { component, props, url, version }, X-Inertia: true, Vary: X-Inertia
X-Inertia GET with another X-Inertia-Version409 with X-Inertia-Location (the client reloads the page)
Partial reload (X-Inertia-Partial-Component + X-Inertia-Partial-Data / -Except)Only the requested props (and always props)
Redirect after PUT / PATCH / DELETE303 instead of 302

Props can be plain values, functions (called when needed, may be async), optional(fn) (only on a partial reload that names it), always(value) (on every visit) and defer(fn, group) (loaded by the client right after the first render). Share data with every page through the share option or ctx.inertia.share(key, value). ctx.inertia.location(url) sends the client to an external URL (409 + X-Inertia-Location).

The asset version is a hash of the Vite manifest when @samveys/vite is installed; set version (a string or a function) to use your own.

Server-side rendering

ts
import { inertia } from '@samveys/inertia'

inertia({
  // Called for the first visit only. Run your SSR bundle (e.g. a Vite SSR build) and return its head and body.
  ssr: async (page) => {
    const { render } = await import('./ssr-bundle.js')
    return render(page) // { head, body }
  },
})

The head is printed by @inertiaHead and the body is placed inside the root element.