Home / Blog / Vue.js with Laravel: 7 Integration Methods Compared (and Which to Use)
Vue.js with Laravel: 7 Integration Methods Compared (and Which to Use)

Vue.js with Laravel: 7 Integration Methods Compared (and Which to Use)

Laravel gives you a fast, batteries-included backend. Vue gives you a reactive frontend. The hard part is deciding how the two should talk to each other, because Laravel supports at least seven different ways to do it, and the right one depends entirely on your project.

This guide walks through all seven, from dropping a single Vue component into a Blade view to running a fully decoupled API. For each you get the setup, the trade-offs, and who it is for. If you just want the short answer, start with the decision table below, then jump to the method that fits.

Benefits of Using Vue.js with Laravel

The collaboration between Vue and Laravel goes beyond simple convenience; it's a strategic alliance forged in the fire of modern web development needs. Let’s go through some of these advantages:

  • Single-Page Application Agility: Vue.js adds dynamism into Laravel's robust backend through reactivity and virtual DOM manipulation, creating SPAs that feel native and lightning-fast. The collaboration eliminates clunky page refreshes and sluggish interactions, delivering enhanced user engagement, reduced server load, and an overall smoother experience.
  • Hot Reloading Magic with Vite: Both Vue and Laravel natively support Vite, offering instant Hot Module Replacement (HMR). This feature reflects code changes in the browser instantaneously without requiring page refreshes, saving developers valuable time and effort.
  • Server-Side Rendering Capabilities: Vue.js and Laravel strategically manage SEO challenges through coordinated approaches like Inertia.js SSR or Nuxt. Laravel pre-renders HTML content for search engine crawlers, while Vue.js handles client-side interactivity.
  • State Management Options: Managing application client-side state is seamless with tools like Pinia. Alternatively, if server-driven state management is your preference, Inertia.js efficiently takes the reins.
  • Vibrant Communities: Both Vue.js and Laravel feature active communities with extensive documentation, robust tooling, and continuous packages for full-stack integration.
  • Future-Proof Foundations: With both Vue 3.5+ and Laravel 12+ constantly evolving to embrace modern web standards, your applications remain performant, type-safe, and maintainable.

Decision Matrix

Use this quick-comparison matrix to evaluate all seven methods against your project requirements:

Method Best for Rendering Front/back coupling Setup effort
Inertia.js v2 New full-stack apps, one team, no separate API SSR + client Tight (single app) Low
Separate API (SPA) Reusing the backend for web + mobile, separate frontend team Client-side Decoupled Medium
Embedded Vue components in Blade Adding interactivity to an existing Laravel app Server + islands Loose Low
Single Blade hosting a full Vue SPA Quick SPA where Laravel just serves the shell Client-side Loose Low
Nuxt + Laravel API SEO-critical frontend, SSR/SSG, separate deploy SSR/SSG Decoupled High
Laravel Splade Blade-first teams wanting SPA feel without writing Vue Server-driven Tight Low
Hybridly Inertia-style DX with extra conventions SSR + client Tight Medium

Opinionated Recommendations

Starting a new Laravel + Vue app in 2026?
Use Inertia.js v2. It gives you SPA-style navigation and Vue components without building or versioning a separate API, and Laravel Breeze scaffolds the whole thing in one command. This is the default recommendation for good reason.

Need the backend to also serve a mobile app, or have a separate frontend team?
Go API-decoupled and treat Laravel as a pure JSON API with Laravel Sanctum for secure authentication.

Adding Vue to an existing Laravel/Blade app?
Do not rewrite anything. Mount embedded Vue components inside the specific Blade views that need interactivity.

SEO-critical, content-heavy frontend?
Pair a Nuxt frontend with a Laravel JSON API backend.

Splade and Hybridly are worth knowing but niche; reach for them only if their specific workflow fits your team. Check their maintenance status before committing to production.

Rendering Modes

To make a well-informed decision about integrating Vue.js with Laravel for your specific use case, it's crucial to grasp the differences between various rendering modes.

Client-Side Rendering (CSR)

Client-Side Rendering Process

In a client-side rendered application, the server acts primarily as a static asset provider. It returns a minimal HTML template containing scripts and styles. Upon receiving the initial payload, the browser downloads and executes the JavaScript bundle, fetching data via API endpoints and constructing the DOM dynamically.

Server-Side Rendering (SSR)

Server-Side Rendering Process

In server-side rendering, the server fetches data and pre-renders complete HTML pages before sending them to the browser. Search engine crawlers can immediately parse the full HTML content without waiting for JavaScript execution. Once received by the browser, Vue hydrates the static HTML to attach dynamic event listeners and state management.

Method 1: Vue.js, Inertia.js v2, and Laravel Integration

Vue.js Inertia.js and Laravel Integration Process

Inertia.js v2 is the modern standard for building full-stack Laravel and Vue applications. It lets you build single-page applications without creating a REST or GraphQL API. You write classic Laravel routes and controllers, return Inertia responses, and render Vue 3 components as views.

Inertia intercepts link clicks, performs lightweight XHR requests, and swaps page components on the fly without triggering full browser reloads.

Key Inertia.js v2 Features

  • Deferred Props: Defer heavy data loading so initial page renders load instantly while non-critical data populates in the background.
  • Prefetching: Automatically prefetch page data on hover or touch to achieve instant route transitions.
  • Built-in Polling: Automatically refresh server data at specified intervals using router.poll() or composables without manual setInterval logic.
  • Infinite Scrolling & Lazy Loading on Scroll: Seamlessly load paged datasets as users scroll down.

Integration Guide

The fastest way to scaffold an Inertia v2 + Vue 3 project is via Laravel Breeze:

# Create a new Laravel project
composer create-project laravel/laravel example-app
cd example-app

# Install Laravel Breeze
composer require laravel/breeze --dev

# Install Inertia with Vue 3 stack
php artisan breeze:install vue

During installation, select Inertia SSR if server-side rendering support is needed for SEO.

Controller Example (app/Http/Controllers/UserController.php):

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Inertia\Inertia;
use Inertia\Response;

class UserController extends Controller
{
    public function index(): Response
    {
        return Inertia::render('Users/Index', [
            'users' => User::paginate(10),
        ]);
    }
}

Vue Page Component (resources/js/Pages/Users/Index.vue):

<script setup>
import { Link } from '@inertiajs/vue3'

defineProps({
  users: Object
})
</script>

<template>
  <div class="p-6">
    <h1 class="text-2xl font-bold mb-4">Users Directory</h1>
    <ul>
      <li v-for="user in users.data" :key="user.id" class="py-2 border-b">
        {{ user.name }} ({{ user.email }})
      </li>
    </ul>
    <div class="mt-4">
      <Link :href="users.prev_page_url" v-if="users.prev_page_url" class="mr-2 text-blue-600">Previous</Link>
      <Link :href="users.next_page_url" v-if="users.next_page_url" class="text-blue-600">Next</Link>
    </div>
  </div>
</template>

Vite Configuration (vite.config.js):

import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [
    laravel({
      input: 'resources/js/app.js',
      refresh: true,
    }),
    vue({
      template: {
        transformAssetUrls: {
          base: null,
          includeAbsolute: false,
        },
      },
    }),
  ],
})

To run the application:

npm run dev
php artisan serve

Summary

  • Advantages: Zero API boilerplate, full SPA user experience, built-in SSR support, powerful Inertia v2 capabilities like prefetching and deferred props.
  • Challenges: Tightly couples frontend to Laravel backend; not designed for standalone public APIs or separate mobile apps.

Method 2: Decoupled Vue.js and Laravel Integration (Separate API)

Separate Laravel and Vue Projects

When your backend needs to power multiple frontends (such as a web SPA, iOS app, and Android app) or when frontend and backend engineering teams operate independently, a fully decoupled API architecture is ideal.

Laravel acts as a stateless JSON API provider using Laravel Sanctum for SPA authentication or API token management. The Vue application operates as a standalone SPA built with Vite and Vue Router.

Integration Guide

1. Setup Laravel Backend API

In your Laravel project, ensure Sanctum is installed for authentication:

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

In routes/api.php:

use App\Http\Controllers\Api\PostController;
use Illuminate\Support\Facades\Route;

Route::middleware('auth:sanctum')->group(function () {
    Route::get('/posts', [PostController::class, 'index']);
});

2. Setup Standalone Vue 3 Frontend

Create a standalone Vue app with Vite:

npm create vue@latest my-vue-app
cd my-vue-app
npm install axios

3. API Consumption in Vue Component (src/components/PostList.vue):

<script setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'

axios.defaults.baseURL = 'http://localhost:8000'
axios.defaults.withCredentials = true // Enables Sanctum cookie authentication

const posts = ref([])
const loading = ref(true)
const error = ref(null)

onMounted(async () => {
  try {
    const response = await axios.get('/api/posts')
    posts.value = response.data
  } catch (err) {
    error.value = 'Failed to load posts from Laravel API.'
  } finally {
    loading.value = false
  }
})
</script>

<template>
  <div>
    <h2>Latest Posts</h2>
    <p v-if="loading">Loading...</p>
    <p v-else-if="error" class="text-red-500">{{ error }}</p>
    <ul v-else>
      <li v-for="post in posts" :key="post.id">{{ post.title }}</li>
    </ul>
  </div>
</template>

Summary

  • Advantages: Total separation of concerns, independent deployment pipelines, reusable API for web and mobile clients.
  • Challenges: Requires managing CORS, authentication state, API versioning, and client-side routing.

Method 3: Embedded Vue Components in Blade Files

Vue components inside Laravel Blade

If you have an existing multi-page Laravel application built with Blade templates, you don't need a full rewrite to introduce Vue. You can embed individual Vue 3 components into specific Blade templates as "islands of interactivity."

Laravel handles server-side routing, controllers, and initial rendering, while Vue enhances specific page elements like interactive calculators, search bars, or complex data tables.

Integration Guide

1. Setup Dependencies

npm install vue@latest @vitejs/plugin-vue

2. Configure Vite (vite.config.js):

import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [
    laravel({
      input: ['resources/css/app.css', 'resources/js/app.js'],
      refresh: true,
    }),
    vue(),
  ],
})

3. Register Components in Entry File (resources/js/app.js):

import './bootstrap'
import { createApp } from 'vue'
import WidgetCalculator from './components/WidgetCalculator.vue'

const app = createApp({})
app.component('widget-calculator', WidgetCalculator)
app.mount('#app')

4. Embed in Blade Template (resources/views/product.blade.php):

<!DOCTYPE html>
<html>
<head>
    <title>Product Page</title>
    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
    <div id="app" class="container mx-auto p-4">
        <h1 class="text-xl font-bold">{{ $product->name }}</h1>
        <p>{{ $product->description }}</p>

        <!-- Embedded Vue Component receiving Blade props -->
        <widget-calculator :base-price="{{ $product->price }}"></widget-calculator>
    </div>
</body>
</html>

5. Vue Component (resources/js/components/WidgetCalculator.vue):

<script setup>
import { ref, computed } from 'vue'

const props = defineProps({
  basePrice: { type: Number, required: true }
})

const quantity = ref(1)
const totalPrice = computed(() => props.basePrice * quantity.value)
</script>

<template>
  <div class="mt-4 p-4 border rounded bg-gray-50">
    <label class="block mb-2 font-semibold">Quantity:</label>
    <input v-model.number="quantity" type="number" min="1" class="border p-1 rounded w-20 mb-2" />
    <p class="text-lg font-bold">Total: ${{ totalPrice.toFixed(2) }}</p>
  </div>
</template>

Summary

  • Advantages: Easiest way to modernize legacy Blade applications incrementally without architectural overhauls.
  • Challenges: No client-side page transitions between Blade views; requires wrapping Vue component mounting targets carefully.

Method 4: Single Blade Hosting a Full Vue.js SPA

Laravel Blade Hosting Vue.js App

In this approach, a single Blade file (resources/views/app.blade.php) serves as the container for a full client-side rendered Vue 3 application. Both frameworks reside inside the same Laravel repository, but Vue Router 4 handles all routing on the client side.

Integration Guide

1. Setup Dependencies

npm install vue@latest vue-router@4 axios @vitejs/plugin-vue

2. Define Catch-All Web Route (routes/web.php):

To prevent 404 errors when users refresh deep URLs, instruct Laravel to direct all web requests to the host Blade view:

Route::get('/{vue_capture?}', function () {
    return view('app');
})->where('vue_capture', '[\/\w\.-]*');

3. Host Blade View (resources/views/app.blade.php):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Vue SPA</title>
    @vite(['resources/js/app.js'])
</head>
<body>
    <div id="app"></div>
</body>
</html>

4. Configure Vue Router (resources/js/router.js):

import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  { path: '/', component: () => import('./pages/Home.vue') },
  { path: '/about', component: () => import('./pages/About.vue') }
]

export default createRouter({
  history: createWebHistory(),
  routes
})

5. Entry Script (resources/js/app.js):

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')

Summary

  • Advantages: Single deployment target in Laravel, clean SPA router workflow.
  • Challenges: Requires manual setup of catch-all web routes and client-side 404 handling; initial page load requires client-side rendering.

Method 5: Nuxt.js and Laravel API Integration

Nuxt.js and Laravel Integration Process

When building an enterprise SEO-critical web application that requires Universal (SSR/SSG) rendering, pair a standalone Nuxt 3 frontend with a Laravel API backend.

Nuxt delivers pre-rendered HTML to search engine crawlers and users instantly while leveraging powerful built-in features like auto-imports, file-based routing, and SSR data fetching (useFetch / $fetch).

To learn more about mastering Laravel backends with Vue and Nuxt, check out our course on Laravel Backends for Vue.js 3.

Integration Guide

1. Fetching Data in Nuxt 3 Component (pages/products/index.vue):

<script setup>
const config = useRuntimeConfig()

const { data: products, pending, error } = await useFetch('/api/products', {
  baseURL: config.public.apiBase // e.g. 'http://localhost:8000'
})
</script>

<template>
  <div class="container mx-auto p-6">
    <h1 class="text-3xl font-bold mb-6">Product Catalog</h1>
    <div v-if="pending">Loading products...</div>
    <div v-else-if="error" class="text-red-600">Error loading catalog.</div>
    <div v-else class="grid grid-cols-3 gap-4">
      <div v-for="product in products" :key="product.id" class="p-4 border rounded shadow-sm">
        <h2 class="text-xl font-semibold">{{ product.name }}</h2>
        <p class="text-gray-600">${{ product.price }}</p>
      </div>
    </div>
  </div>
</template>

Summary

  • Advantages: Top-tier SEO performance, full SSR/SSG capabilities, auto-imported components, modern Nuxt DX.
  • Challenges: Higher complexity due to two separate Node.js / PHP deployment environments.

Method 6: Laravel Splade

Laravel Splade integration process

Laravel Splade allows developers to create SPA-like experiences using Blade templates instead of writing standalone Vue SFCs. Under the hood, Splade uses Vue 3 and renderless components to handle form submissions, modals, and dynamic transitions over AJAX.

Integration Guide

composer require protonemedia/laravel-splade
php artisan splade:install

In your Blade template:

<x-splade-form action="/users">
    <x-splade-input name="name" label="Name" />
    <x-splade-input name="email" label="Email Address" />
    <x-splade-submit class="mt-4" />
</x-splade-form>

Note: Splade is a niche option maintained by the community. Check repository activity and compatibility before starting major long-term production builds.

Method 7: Hybridly

Laravel Hybridly rendering cycle

Hybridly is an alternative architecture similar to Inertia.js. It pairs Laravel with Vue 3, providing explicit TypeScript integration, automated routing generation, and custom component composables.

Integration Guide

composer require hybridly/laravel
php artisan hybridly:install
<script setup lang="ts">
defineProps<{
  user: Array<{ id: number; name: string }>
}>()
</script>

<template>
  <div>
    <h1>Welcome, {{ user.name }}</h1>
  </div>
</template>

Note: Like Splade, Hybridly offers unique conventions but remains a specialized tool compared to the official Inertia.js ecosystem.

Frequently Asked Questions (FAQ)

What is the best way to use Vue with Laravel?

For most new projects, Inertia.js v2. It renders Vue 3 components straight from your Laravel controllers, gives you single-page navigation, and needs no separate REST or GraphQL API. Go with a decoupled Vue SPA and a Laravel JSON API instead when the same backend has to serve mobile apps or a separate frontend team, or embed Vue components in Blade when you are adding interactivity to an app that already exists. There is no universal winner, the best method is the one that matches your team and product.

Should I use Inertia or a separate API with Laravel and Vue?

Use Inertia if one team owns the whole application and you do not need a public API; it is simpler, faster to ship, and requires zero API boilerplate. Use a separate API if you need to serve multiple clients (web plus mobile apps) or have an independent frontend engineering team.

Can I use Vue 3 with Laravel Blade without a build step?

Yes. Include Vue from a CDN via a <script> tag and mount an app on an element in your Blade view using createApp(...).mount('#app'). It works fine for light interactivity, but for real production applications, use Vite.

How do I use Vue inside a Laravel Blade view?

Mount individual Vue 3 components inside the specific Blade templates that need them, as islands of interactivity. Register the component in your resources/js/app.js entry file, load it with the @vite directive, and pass data down from Blade through props. Laravel keeps handling routing and the initial render while Vue powers only the interactive parts. Method 3 above has the full setup.

Is Laravel Mix still the way to compile Vue?

No. Modern Laravel applications use Vite by default. Laravel Mix is legacy; while it still works on older projects, all new integrations should use Vite with @vitejs/plugin-vue.

Do Vue and Laravel work with Vite?

Yes, and it is the default. Laravel ships the laravel-vite-plugin, you add @vitejs/plugin-vue for single-file components, and the @vite Blade directive serves it all. You get hot module replacement in development and hashed, cache-busted assets in production. Laravel Mix is legacy and not recommended for new work.

How do I handle authentication between Vue and Laravel?

For an Inertia app, use Laravel's standard session auth, which the Vue starter kit and Breeze both scaffold for you. For a decoupled Vue SPA on the same top-level domain, use Laravel Sanctum cookie-based auth, which means you set withCredentials on requests, call the CSRF cookie endpoint first, and list your frontend under Sanctum's stateful domains. For mobile apps or third-party clients, issue Sanctum API tokens instead.

How do I add real-time updates to a Laravel and Vue app?

Run Laravel Reverb as your WebSocket server and subscribe from Vue with the official @laravel/echo-vue package. Configure it once with configureEcho({ broadcaster: 'reverb' }), then listen in any component with the useEcho composable for private channels, or useEchoPublic and useEchoPresence for the others. It cleans up subscriptions on unmount, so you get live notifications, chat, and dashboards without polling the server. The real-time section above has the full setup.

Do I need Nuxt to use Vue with Laravel?

No. Nuxt only makes sense when you require full SSR/SSG and a separately deployed frontend for extreme SEO demands. For most Laravel + Vue applications, Inertia.js or embedded components are far simpler.

What is the easiest way to add Vue to an existing Laravel app?

Mount individual Vue components in the specific Blade templates that need interactivity. You keep all your existing routes, controllers, and middleware, adding client-side dynamic components only where required.

How do I deploy a Laravel and Vue application?

Run npm run build in your release pipeline so Vite outputs production assets, then deploy. Inertia, embedded-component, and single-Blade setups deploy as one Laravel app, plus php artisan inertia:start-ssr under a process manager if you use Inertia SSR. A decoupled Vue SPA or Nuxt frontend deploys separately from the API, with CORS and the API base URL set through environment variables. The deployment section above has the full checklist.

Where to go from here

Whichever method fits, the Vue skills underneath it are the same, like components, reactivity, Pinia, and Vue Router. If that side of the stack is the shaky part for you, the Vue.js 3 Master Class builds a full production app with those exact pieces, and the free Learn Vue tutorial is a faster on-ramp if you are brand new to Vue.

Pick the integration that gets your product in front of users fastest, then optimize once it is real.

Conclusion

Combining Vue.js and Laravel gives you one of the most versatile full-stack toolkits available in modern web development. Whether you choose Inertia.js v2 for an effortless SPA workflow, a decoupled API with Sanctum for multi-platform delivery, or embedded Blade components for incremental enhancements, both ecosystems provide world-class developer experiences and performance.

Evaluate your team structure, SEO requirements, and target platforms, then pick the integration pattern that gets your product to market fastest.

Ready to take your Vue.js and Laravel expertise to the master level? Dive into our comprehensive Vue.js 3 Master Class to build production-ready applications with modern full-stack workflows!

Related Courses

Start learning Vue.js for free

Comments

Latest Vue School Articles

5 Component Design Patterns to Boost Your Vue.js Applications

5 Component Design Patterns to Boost Your Vue.js Applications

5 essential Vue.js component design patterns, including branching components, slots usage, list organization, smart vs dumb components, and form handling - perfect for both Vue beginners and experienced developers looking to improve code maintainability and scalability.
Vibe Coding a Collaborative Editor with Comment Support with Nuxt UI and Jazz

Vibe Coding a Collaborative Editor with Comment Support with Nuxt UI and Jazz

Why I built a Nuxt + Jazz powered real time editor, how you can use it, and a list of takeaways on building with the help of AI.
VueSchool logo

Our goal is to be the number one source of Vue.js knowledge for all skill levels. We offer the knowledge of our industry leaders through awesome video courses for a ridiculously low price.

More than 250.000 users have already joined us. You are welcome too!

Follow us on Social