marko/inertia
Inertia.js protocol integration for the Marko Framework. It renders Inertia page objects as JSON for Inertia requests, emits the initial HTML shell for browser visits, integrates with marko/vite for frontend assets, and provides shared props, lazy props, partial reloads, flash messages, asset version checks, and optional SSR.
Installation
Section titled “Installation”composer require marko/inertiamarko/inertia depends on marko/vite, marko/session, marko/routing, marko/config, and marko/env.
Configuration
Section titled “Configuration”Configure via config/inertia.php:
return [ 'version' => null, 'assetEntry' => null, 'ssr' => [ 'enabled' => env('INERTIA_SSR_ENABLED', false), 'url' => env('INERTIA_SSR_URL', 'http://localhost:13714'), ],];| Key | Purpose |
|---|---|
version | Asset version included in every Inertia page object. Set to null to disable version mismatch handling. |
assetEntry | Default Vite entry used by render() when no $assetEntry argument is passed. Frontend companion packages (marko/inertia-react, marko/inertia-vue, marko/inertia-svelte) overlay this slot via config/inertia.php so installing one swaps the entry without code changes. |
ssr.enabled | When true, the initial browser response attempts to render through the configured Inertia SSR server. |
ssr.url | URL used by the SSR client when SSR is enabled. |
Inject Inertia into a controller and return render() from route actions:
use Marko\Inertia\Inertia;use Marko\Routing\Http\Request;use Marko\Routing\Http\Response;
class DashboardController{ public function __construct( private readonly Inertia $inertia, ) {}
public function index(Request $request): Response { return $this->inertia->render($request, 'Dashboard', [ 'user' => ['name' => 'Paulo'], 'stats' => fn (): array => ['orders' => 12], ]); }}For an Inertia request (X-Inertia: true), render() returns JSON:
{ "component": "Dashboard", "props": { "user": { "name": "Paulo" } }, "url": "/", "version": null}For a normal browser visit, render() returns the initial HTML shell with the page JSON embedded and Vite head tags included.
Asset Entries
Section titled “Asset Entries”The Vite entry resolves in this order:
- The
$assetEntryargument passed torender()(highest priority). - The
inertia.assetEntryconfig slot, typically populated by a frontend companion package (marko/inertia-react,marko/inertia-vue,marko/inertia-svelte). - The
vite.entryfallback frommarko/vite.
Pass an asset entry per call to override the configured default:
return $this->inertia->render( request: $request, component: 'Dashboard', props: ['user' => ['name' => 'Paulo']], assetEntry: 'app/react-web/resources/js/app.jsx',);Shared Props
Section titled “Shared Props”Use share() to attach props to every response:
$this->inertia->share('auth', [ 'user' => [ 'name' => 'Paulo', ],]);
$this->inertia->share([ 'appName' => 'Marko', 'locale' => 'en',]);Shared props are merged after the built-in errors and flash props, then page props are merged last.
Lazy Props and Partial Reloads
Section titled “Lazy Props and Partial Reloads”Props may be closures. They are evaluated for full loads and for partial reloads that include the prop:
return $this->inertia->render($request, 'Reports/Index', [ 'filters' => $filters, 'results' => fn (): array => $this->reportService->search($filters),]);The package supports X-Inertia-Partial-Component, X-Inertia-Partial-Data, and X-Inertia-Partial-Except. The errors and flash props remain available during partial reloads.
Flash Messages
Section titled “Flash Messages”Flash messages are stored in the active session and exposed through the flash prop:
$this->inertia->flash('success', 'Settings saved.');Multiple messages may be flashed under the same key:
$this->inertia->flash('notice', [ 'Profile updated.', 'Notification settings saved.',]);Redirects
Section titled “Redirects”Use location() for external or non-Inertia redirects:
return $this->inertia->location('https://example.com');This returns a 409 response with the X-Inertia-Location header.
Middleware
Section titled “Middleware”Add InertiaMiddleware to controllers that return Inertia responses:
use Marko\Inertia\Inertia;use Marko\Inertia\Middleware\InertiaMiddleware;use Marko\Routing\Attributes\Get;use Marko\Routing\Attributes\Middleware;use Marko\Routing\Http\Request;use Marko\Routing\Http\Response;
#[Middleware(InertiaMiddleware::class)]class DashboardController{ public function __construct( private readonly Inertia $inertia, ) {}
#[Get('/dashboard')] public function index(Request $request): Response { return $this->inertia->render($request, 'Dashboard'); }}The middleware adds Vary: X-Inertia, converts non-GET Inertia redirects from 302 to 303, and returns 409 with X-Inertia-Location when a GET request sends a stale X-Inertia-Version.
Server-Side Rendering
Section titled “Server-Side Rendering”When inertia.ssr.enabled is true, the HTML shell posts the page object to inertia.ssr.url. A successful SSR response must return JSON with a non-empty body string and an optional head string:
{ "head": "<title>Dashboard</title>", "body": "<div id=\"app\">...</div>"}If the SSR transport fails or returns an unusable response, Marko falls back to the client-rendered HTML shell. Configuration errors still throw loud Marko exceptions.
Errors
Section titled “Errors”Following Marko’s loud-errors principle, missing or invalid Inertia configuration throws rather than silently degrading.
Marko\Inertia\Exceptions\InertiaConfigurationException is thrown when:
inertia.versionis missing, or is not a string, number, ornull.inertia.ssr.enabledis missing or invalid.inertia.ssr.urlis missing, invalid, or empty when SSR rendering is attempted.
SSR transport failures return null from the transport layer so the page can fall back to client rendering.
API Reference
Section titled “API Reference”namespace Marko\Inertia;
use Marko\Routing\Http\Request;use Marko\Routing\Http\Response;
class Inertia{ public function share(array|string $key, mixed $value = null): void; public function flash(string $key, string|array $value): void; public function render(Request $request, string $component, array $props = [], ?string $assetEntry = null): Response; public function location(string $url): Response; public function isInertiaRequest(Request $request): bool; public function version(): ?string;}namespace Marko\Inertia\Ssr;
interface SsrTransportInterface{ public function post(string $url, string $body): ?string;}Related Packages
Section titled “Related Packages”marko/vite- renders frontend asset tags for the Inertia HTML shellmarko/session- stores flash messagesmarko/routing- provides requests, responses, and middlewaremarko/config- provides the configuration repositorymarko/env- provides theenv()helper used inconfig/inertia.php