inertiajs/inertia-laravel
Official Laravel adapter for Inertia.js. Build modern single-page apps using classic server-side routing and controllers, without building an API. Provides Inertia responses, shared props, middleware helpers, and integration with Laravel features.
Installation:
composer require inertiajs/inertia-laravel
npm install @inertiajs/inertia @inertiajs/inertia-laravel
Run migrations and publish config:
php artisan inertia:install
First Page Render:
In a controller, use the Inertia::render() facade:
use Inertia\Inertia;
public function show()
{
return Inertia::render('Dashboard', [
'users' => User::all(),
]);
}
First Vue/React Component:
Create a file at resources/js/Pages/Dashboard.vue:
<template>
<div>
<h1>Dashboard</h1>
<ul>
<li v-for="user in users" :key="user.id">
{{ user.name }}
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
users: Array,
}
}
</script>
Route Configuration:
Route::get('/dashboard', [DashboardController::class, 'show'])
->middleware(['auth', 'verified']);
Server-Side Data Fetching:
// Controller
return Inertia::render('Posts/Index', [
'posts' => Post::with('author')->latest()->get(),
'filters' => request()->only(['search', 'category']),
]);
<!-- Posts/Index.vue -->
<script>
export default {
props: {
posts: Array,
filters: Object,
}
}
</script>
Page Rendering Patterns:
return Inertia::render('PageName', ['prop1' => $value1]);
// In AppServiceProvider boot()
Inertia::share([
'auth' => fn () => [
'user' => Auth::user(),
],
]);
Navigation & Redirects:
<Link href="/dashboard">Dashboard</Link>
return redirect()->route('dashboard')->withInertiaFlash([
'message' => 'Success!',
]);
Data Loading Strategies:
return Inertia::render('Profile', [
'user' => User::with('posts', 'comments')->find($id),
]);
return Inertia::render('Posts/Index', [
'posts' => Post::all(),
'comments' => fn () => Comment::whereIn('post_id', $postIds)->get(),
]);
<script>
export default {
props: {
posts: Array,
comments: { default: () => [] },
},
async created() {
await this.$inertia.partial(this.$page.props.comments);
}
}
</script>
Component-Based Architecture:
// Parent page
return Inertia::render('Layout', [
'child' => Inertia::render('ChildComponent', ['data' => $data]),
]);
return Inertia::location('/dashboard', [
'partials' => [
'stats' => Inertia::render('StatsCard', ['data' => $newData]),
],
]);
Authentication:
// In App\Http\Middleware\HandleInertiaRequests
public function root()
{
return Inertia::root(fn () => match (Auth::user()) {
null => 'Login',
default => 'Dashboard',
});
}
Form Handling:
// Controller
public function store(Request $request)
{
$validated = $request->validate([...]);
$post = Post::create($validated);
return redirect()->route('posts.show', $post)
->withInertiaFlash([
'success' => 'Post created!',
]);
}
<!-- PostCreate.vue -->
<script>
export default {
props: {
errors: Object,
flash: Object,
}
}
</script>
API Integration:
// Controller
public function getData()
{
$response = Http::get('https://api.example.com/data');
return Inertia::render('DataPage', [
'apiData' => $response->json(),
]);
}
Testing:
// Test
$response = $this->get('/dashboard');
$response->assertInertia(fn (AssertableInertia $page) => $page
->component('Dashboard')
->has('users', 3)
);
Middleware Priority:
HandleInertiaRequests middleware is registered after authentication middleware:
// kernel.php
'web' => [
\App\Http\Middleware\Authenticate::class,
\Inertia\Middleware::class, // <-- After auth
],
Shared Data Timing:
Inertia::share([
'auth' => fn () => [
'user' => Auth::user(),
'can' => fn (string $ability) => Auth::user()->can($ability),
],
]);
Deferred Props:
// Wrong (string)
'comments' => 'App\Http\Controllers\CommentController@getComments',
// Correct (callable)
'comments' => fn () => Comment::all(),
rescue() for error handling:
'comments' => fn () => Comment::all()->rescue(fn () => []),
Flash Data:
session()->flash('temp_data', $data);
withInertiaFlash() for Inertia-specific flash messages.SSR (Server-Side Rendering):
npm run dev
Inertia::disableSsr();
Inspect Page Props:
// In middleware or controller
\Log::info('Page props:', [
'props' => $request->inertia()->props,
'url' => $request->url(),
]);
Check Deferred Props:
// In controller
$deferred = $request->inertia()->deferred;
\Log::info('Deferred props:', $deferred);
Middleware Debugging:
dd($request->inertia()) to inspect the Inertia request object.Vue/React DevTools:
$page object in browser console to see all props and partials.Custom Page Transforms:
// In AppServiceProvider
Inertia::pageTransform(function (Page $page) {
if ($page->component === 'Dashboard') {
$page->with([
'extraData' => fn () => Cache::get('dashboard_extra'),
]);
}
return $page;
});
Custom Inertia Responses:
// In AppServiceProvider
Inertia::macro('customResponse', function ($component, $props = []) {
return response()->inertia($component, $props, 200, [
'X-Custom-Header' => 'value',
]);
});
Middleware Hooks:
// In HandleInertiaRequests middleware
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'requestData' => $request->only(['search', 'page']),
]);
}
Testing Helpers:
// In TestCase
use function Inertia\Testing\AssertableInertia;
public function assertInertiaPage(AssertableInertia $page, string $component, array $props = [])
{
$page->component($component);
foreach
How can I help you explore Laravel packages today?