Laravel 12 combined with Inertia.js 2 and Vue 3 provides a clean and efficient way
to build modern single-page applications while keeping server-side routing,
middleware, and authentication fully intact.
💡 This stack is ideal for developers who want Vue reactivity with Laravel’s
backend power — without building or maintaining APIs.
Why Use Laravel with Inertia.js and Vue?
Inertia.js acts as a glue layer between Laravel and Vue, allowing you to build
SPA-like experiences using classic controllers and routes.
No REST or GraphQL APIs required
Laravel routing and controllers stay intact
SEO-friendly server-driven responses
Vue 3 reactivity with minimal boilerplate
Inertia Server-Side Setup in Laravel 12
Create a Fresh Laravel Project
composer create-project laravel/laravel inertia-vue-app
cd inertia-vue-app
Install Inertia Laravel Adapter
composer require inertiajs/inertia-laravel
Create Inertia Middleware
php artisan inertia:middleware
This middleware enables shared props and handles Inertia-specific request logic.
Register Middleware in Laravel 12
use App\Http\Middleware\HandleInertiaRequests;
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
HandleInertiaRequests::class,
]);
})
⚠️ Skipping this step will cause Inertia responses to fail silently.
Root Blade Template for Inertia
Inertia requires a single root Blade template that bootstraps the Vue application.
<!-- resources/views/app.blade.php -->
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
@vite('resources/js/app.js')
@inertiaHead
</head>
<body>
@inertia
</body>
</html>
The @inertiaHead directive allows Vue pages to control meta tags
dynamically for SEO.
Basic Inertia Route Example
use Inertia\Inertia;
Route::get('/', function () {
return Inertia::render('Home');
});
Laravel returns a Vue page component instead of a Blade view or JSON response.
Client-Side Setup with Vue 3
Install Required NPM Packages
npm install @inertiajs/vue3
npm install @vitejs/plugin-vue
Inertia Application Bootstrap
Configure the main Vue entry file that initializes Inertia.
// resources/js/app.js
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'
createInertiaApp({
resolve: name => {
const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
return pages[`./Pages/${name}.vue`]
},
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el)
},
})
This setup dynamically loads Vue pages and mounts them using the Inertia plugin.
Create Your First Vue Page
<!-- resources/js/Pages/Home.vue -->
<template>
<div>Home</div>
</template>
<script setup>
</script>
Visiting the root URL now renders this Vue component automatically.
Vite Configuration for Laravel, Vue, and Tailwind
Vite handles asset compilation, hot reloading, and Vue file processing.
import { defineConfig } from "vite";
import laravel from "laravel-vite-plugin";
import tailwindcss from "@tailwindcss/vite";
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [
laravel({
input: ["resources/css/app.css", "resources/js/app.js"],
refresh: true,
}),
tailwindcss(),
vue(),
],
server: {
watch: {
ignored: ["**/storage/framework/views/**"],
},
},
});
⚠️ The Vite input paths must match the assets loaded in your Blade root file.
Final Thoughts
Laravel 12 with Inertia.js 2 and Vue 3 delivers a highly maintainable, SEO-friendly,
and scalable SPA architecture. You gain the benefits of Vue reactivity while
preserving Laravel’s backend simplicity.
This stack is especially effective for dashboards, admin panels, and SaaS
platforms where performance and developer experience matter.