Vue 3 Composition API: A Practical Introduction
setup(), ref vs reactive, and reusable composables — a practical introduction to Vue 3's Composition API for developers coming from Options API or another framework.
Inertia.js lets you build a Vue.js frontend backed by a Laravel application without building a separate JSON API — no REST endpoints, no client-side routing library, just Laravel controllers returning Vue pages directly. It's the fastest path to a modern SPA feel from an existing Laravel codebase.
A normal SPA needs a JSON API and a client-side router to reconstruct pages. Inertia skips both: your Laravel controller returns an Inertia response that names a Vue component and passes it props, exactly like returning a Blade view — except the "view" is a full Vue single-file component, and navigation between pages happens via XHR without a full page reload.
composer require inertiajs/inertia-laravel
npm install @inertiajs/vue3
// resources/js/app.js
import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/vue3';
createInertiaApp({
resolve: (name) => import(`./Pages/${name}.vue`),
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el);
},
});
class PostController extends Controller
{
public function index()
{
return inertia('Posts/Index', [
'posts' => Post::latest()->paginate(10),
]);
}
}
<!-- resources/js/Pages/Posts/Index.vue -->
<script setup>
defineProps({ posts: Object });
</script>
<template>
<div v-for="post in posts.data" :key="post.id">{{ post.title }}</div>
</template>
Notice there's no fetch() anywhere — the props just show up, exactly like a Blade view's variables would.
<script setup>
import { useForm } from '@inertiajs/vue3';
const form = useForm({ title: '', body: '' });
function submit() {
form.post('/posts');
}
</script>
<template>
<form @submit.prevent="submit">
<input v-model="form.title" />
<span v-if="form.errors.title">{{ form.errors.title }}</span>
<button :disabled="form.processing">Save</button>
</form>
</template>
Laravel's normal validation errors flow straight into form.errors — the same $request->validate() you'd write for a Blade form works completely unchanged.
Inertia is an excellent fit when Laravel and the frontend are the same team, same deploy, same codebase — you get SPA navigation and a modern component model without maintaining a separate API. If you need a truly independent frontend (a separate mobile app, a third-party integration), a real JSON API plus Sanctum is still the better architecture.
setup(), ref vs reactive, and reusable composables — a practical introduction to Vue 3's Composition API for developers coming from Options API or another framework.
Why Pinia replaced Vuex as Vue's recommended state management library, and how to set up stores in both Options and Composition API styles.