Support the ongoing development of →

Enhancing Laravel and Inertia.js with TypeScript and Vue 3's Composition API to build a Powerful SPA

6 Nov, 2023 5 min read 280 views


Laravel, when combined with Inertia.js, offers a powerful duo for creating modern single-page applications that rival the complexity of full frontend frameworks using Vue.js or React. This article guides you through the process of integrating Laravel with Inertia.js and Vue 3, then goes a step further by introducing TypeScript within Vue's Composition API.


  • Composer installed on your local machine
  • Node.js and npm/yarn installed
  • Basic knowledge of Laravel, Vue.js, and TypeScript

Setting Up Laravel with Inertia.js

Create a new Laravel project and navigate to your project directory:

composer create-project laravel/laravel inertia-example
cd inertia-example

Install Inertia.js with Composer:

composer require inertiajs/inertia-laravel

And publish the Inertia.js configuration:

php artisan inertia:middleware

Make sure to register the Inertia middleware by adding it at the end of the web middleware group in app/Http/Kernel.php.

Integrating Vue 3 and TypeScript

With Laravel set up, let's shift focus to the frontend. Install Vue 3 and Inertia.js's Vue adapter:

npm install vue @inertiajs/vue3 @types/ziggy-js lodash --save-dev

Add TypeScript and its Vue plugin:

npm install typescript @vitejs/plugin-vue vue-tsc --save-dev

Set up your tsconfig.json for TypeScript:

        "types": ["vite/client"]  

Let's now create the Typescript types required:

Head to resources/js and create a directory named types, within the directory create a TS file named global.d.ts and copy the following content in the file:

import { PageProps as InertiaPageProps } from '@inertiajs/core';
import { AxiosInstance } from 'axios';
import ziggyRoute, { Config as ZiggyConfig } from 'ziggy-js';
import { PageProps as AppPageProps } from './';

declare global {
    interface Window {
        axios: AxiosInstance;

    var route: typeof ziggyRoute;
    var Ziggy: ZiggyConfig;

declare module 'vue' {
    interface ComponentCustomProperties {
        route: typeof ziggyRoute;

declare module '@inertiajs/core' {
    interface PageProps extends InertiaPageProps, AppPageProps {}

Install Ziggy for route handling in Vue

Ziggy is a package developed by Tighten for Laravel in order to share the routes from routes/web.php with the client side.

composer require tightenco/ziggy

Updating the Frontend Build Tools

Configure Vite to work with TypeScript by adjusting your vite.config.js:

import { defineConfig } from 'vite';  
import laravel from 'laravel-vite-plugin';  
import vue from '@vitejs/plugin-vue';  
import path from 'path';  
export default defineConfig({  
            "input": [  
            "refresh": true  
            template: {  
                transformAssetUrls: {  
                    base: null,  
                    includeAbsolute: false,  

Modify package.json to include scripts for TypeScript compilation and Vite's build process:

"scripts": {  
    "dev": "vite",  
    "build": "vue-tsc --noEmit && vite build",  
    "ts-check": "vue-tsc --noEmit"  

Update your entry point to TypeScript in resources/js/app.ts and make sure to change the extension of resources/js/app.js to app.ts as well as for bootstrap.js to bootstrap.ts.

import './bootstrap';  
import '../css/app.css';  
import { createApp, h, DefineComponent } from 'vue';  
import { createInertiaApp } from '@inertiajs/vue3';  
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';  
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/';  
const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';  
    title: (title) => `${title} - ${appName}`,  
    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob<DefineComponent>('./Pages/**/*.vue')),  
    setup({ el, App, props, plugin }) {  
        createApp({ render: () => h(App, props) })  
            .use(ZiggyVue, Ziggy)  
    },    progress: {  
        color: '#4B5563',  

Defining Routes and Views

Create the layout file in resources/views/app.blade.php:

<!DOCTYPE html>  
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" class="h-full bg-gray-100">  
    <meta charset="utf-8">  
    <meta name="viewport" content="width=device-width, initial-scale=1">  
    <title inertia>{{ config('', 'Laravel') }}</title>  
    <!-- Fonts -->  
    <link rel="preconnect" href="">  
    <link href=",500,600&display=swap" rel="stylesheet" />  
    <!-- Scripts -->  
    @vite(['resources/js/app.ts', "resources/js/Pages/{$page['component']}.vue"])  
<body class="font-sans antialiased h-full">  

Define your Inertia routes in routes/web.php:

Route::get('/', function () {  
    return Inertia\Inertia::render('Welcome');  
Route::get('/about', function () {  
    return Inertia\Inertia::render('About');  

Make sure you create the corresponding Vue components in the resources/js/Pages directory.

Using TypeScript with Vue's Composition API

To leverage TypeScript within your Vue components, use the <script setup lang="ts"> syntax, which simplifies the Composition API usage.

Example resources/js/Pages/Welcome.vue:

<script setup lang="ts">  
import { ref } from 'vue';  
import { Link } from '@inertiajs/vue3';  
const greeting = ref('Welcome to Your Vue.js + TypeScript App');  

    <h1>{{ greeting }}</h1>  
    <Link href="/about">Go to About page</Link>  

And another one for About.vue:

    <h1>{{ greeting }}</h1>  
    <Link href="/">Go to Welcome page</Link>  
<script setup lang="ts">  
import { ref } from 'vue';  
import { Link } from '@inertiajs/vue3';  
const greeting = ref('Welcome to About page');  


Integrating TypeScript with Laravel, Inertia.js, and Vue 3's Composition API may seem daunting at first, but it's a worthwhile investment for development efficiency and performance gains. With this setup, you get the type-checking prowess of TypeScript, the reactivity and composability of Vue 3, and the seamless interactivity provided by Inertia.js, all within a robust Laravel application.

For further exploration, consider delving into advanced TypeScript features, state management with Vuex or Pinia, and automatic type generation for Inertia's route linking.

Last updated 3 weeks ago.
Like this article? Let the author know and give them a clap!
bcryp7 (Alberto Rosas) Hi, I'm Alberto. As a Senior Software Engineer and Consultant.

Other articles you might like

November 22nd 2023

Using Stability AI in Laravel

Stability AI is an AI company that develops open-source models, such as Stability Diffusion XL, whi...

Read article
January 16th 2023

Laravel Collections: The Artisan's Guide

Introduction Laravel Collections are really powerful for working with arrays of data. They provide a...

Read article
November 16th 2023

Create a Laravel package on your local environment

How to set up a local development environment to test your package classes or utilities within a lo...

Read article

We'd like to thank these amazing companies for supporting us

Your logo here?

The Laravel portal for problem solving, knowledge sharing and community building.

© 2023 - All rights reserved.