inertiajs/inertia-laravel
Laravel adapter for Inertia.js: build modern single-page apps using classic server-side routing and controllers. Provides middleware, helpers, and response rendering to connect Laravel with your Vue/React/Svelte pages while keeping the full Laravel backend workflow.
Installation:
composer require inertiajs/inertia-laravel
npm install @inertiajs/inertia @inertiajs/inertia-laravel
Follow the official installation guide for Vite/Webpack setup.
Publish Config:
php artisan vendor:publish --provider="Inertia\InertiaServiceProvider" --tag=config
This generates config/inertia.php for customization.
First Route/Controller:
// routes/web.php
Route::get('/dashboard', function () {
return Inertia::render('Dashboard');
});
First Vue/React Page:
<!-- resources/js/Pages/Dashboard.vue -->
<template>
<h1>Welcome to Dashboard</h1>
</template>
// Controller or route closure
return Inertia::render('Profile', [
'user' => User::find(1),
'stats' => $this->getUserStats(), // Custom method
]);
Page Rendering:
// Basic render
return Inertia::render('PageName');
// With props
return Inertia::render('PageName', ['key' => 'value']);
// With shared data (via middleware)
Inertia::share(['auth' => fn() => Auth::user()]);
Navigation:
// Redirect with inertia
return redirect()->route('dashboard')->withInertia([
'message' => 'Success!'
]);
// Link in Vue
<Link href="/dashboard">Go to Dashboard</Link>
Deferred Props (for lazy-loading):
// In controller
return Inertia::render('Page', [
'user' => User::find(1),
'posts' => Post::query()->take(10)->get(),
'deferred' => fn() => Post::query()->skip(10)->get(),
]);
// In Vue
<template>
<div @inertia-preload="posts">
<!-- Render posts -->
</div>
</template>
Middleware:
// HandleInertiaRequests middleware (auto-included)
// Custom middleware for shared data
public function share(Request $request): array
{
return [
'appName' => config('app.name'),
];
}
Testing:
// Test response assertions
$response->assertInertia(fn (AssertableInertia $page) =>
$page->component('Dashboard')
->has('user', fn ($user) => $user['name'] === 'John')
);
SSR (Server-Side Rendering):
// Check SSR health
if (!Inertia::isHealthy()) {
abort(503);
}
// SSR-specific rendering
return Inertia::render('Page', [], false, [
'ssr' => true,
]);
Flash Data:
// Set flash data
return redirect()->route('dashboard')->withInertiaFlash([
'success' => 'Operation completed!',
]);
// Access in Vue
<template>
<div v-if="$page.props.flash.success">
{{ $page.props.flash.success }}
</div>
</template>
Custom URL Resolution:
// config/inertia.php
'url' => [
'resolver' => App\Services\CustomUrlResolver::class,
],
Missing Shared Data:
HandleInertiaRequests) or via Inertia::share().app/Http/Middleware/HandleInertiaRequests.php:
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'key' => 'value',
]);
}
Deferred Props Not Loading:
@inertia-preload or incorrect prop names.<div @inertia-preload="deferredPropName">
<!-- Content -->
</div>
Flash Data Persistence:
withInertiaFlash().withInertiaFlash() instead of Laravel’s with():
return redirect()->route('dashboard')->withInertiaFlash(['error' => 'Failed']);
SSR Issues:
php artisan inertia:check-ssr or ensure ssr.ensure_bundle_exists is configured.Prop Modifiers Ignored:
once() or reload() modifiers incorrectly.Inertia::merge() or Inertia::scroll():
return Inertia::render('Page', [], false, [
'merge' => ['key' => 'value'],
'scroll' => ['x' => 0, 'y' => 0],
]);
Inspect Props:
dd($page->props) in Vue’s created() lifecycle to debug props.Check SSR:
php artisan inertia:check-ssr to verify SSR setup.Middleware Debugging:
dd($this->share($request)) to HandleInertiaRequests to inspect shared data.Network Tab:
X-Inertia: true header in the response to confirm Inertia is working.Custom Prop Providers:
ProvidesInertiaProps interface for reusable prop logic:
class UserProvider implements ProvidesInertiaProps
{
public function getProps(Request $request): array
{
return ['user' => Auth::user()];
}
}
HandleInertiaRequests:
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'user' => (new UserProvider())->getProps($request),
]);
}
Custom URL Resolver:
Inertia\Routing\UrlResolver for dynamic URL generation:
class CustomUrlResolver extends UrlResolver
{
public function resolve(string $page): string
{
// Custom logic
return parent::resolve($page);
}
}
config/inertia.php:
'url' => [
'resolver' => App\Services\CustomUrlResolver::class,
],
Testing Helpers:
AssertableInertia for complex assertions:
$response->assertInertia(fn (AssertableInertia $page) =>
$page->component('Dashboard')
->has('user.id', 1)
->missing('deletedUser')
);
Partial Requests:
// In Vue
<template>
<div @inertia-preload="posts">
<button @click="$inertia.partial('posts', { page: 2 })">Load More</button>
</div>
</template>
How can I help you explore Laravel packages today?