How to Upload File in Laravel 12 with Inertia.js and Vue.js

How to Upload File in Laravel 12 with Inertia.js and Vue.js

Absolutely! Here’s a 100% original and detailed blog post (~1500 words) for the title:


How to Upload File in Laravel 12 with Inertia.js and Vue.js

In modern web applications, file uploading is a common requirement—whether it’s user profile pictures, PDFs, invoices, or media files. When you’re building a full-stack application using Laravel 12, Inertia.js, and Vue.js, you can handle file uploads efficiently without setting up a separate API.

This tutorial will walk you through uploading files using Laravel 12 and Inertia.js with Vue 3, covering everything from the frontend setup to backend processing and validation.


What You’ll Learn

  • Setting up Laravel 12 with Inertia.js and Vue.js
  • Creating a file upload form in Vue
  • Handling form submission via Inertia
  • Validating and saving the uploaded file in Laravel
  • Displaying success or error messages

Prerequisites

Before we begin, make sure you have:

  • PHP 8.2+ and Composer installed
  • Node.js and npm installed
  • Laravel 12 project set up
  • Inertia.js and Vue 3 installed

If you’re starting from scratch, install Laravel like this:

composer create-project laravel/laravel file-upload-app
cd file-upload-app

Step 1: Install Inertia.js and Vue.js

Install the required packages:

composer require inertiajs/inertia-laravel
npm install @inertiajs/inertia @inertiajs/vue3 vue@3

Publish Inertia’s middleware:

php artisan inertia:middleware

Register the middleware in app/Http/Kernel.php under the web group:

\App\Http\Middleware\HandleInertiaRequests::class,

Then set up your Inertia Vue app in resources/js/app.js:

import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'

createInertiaApp({
  resolve: name => require(`./Pages/${name}.vue`),
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .mount(el)
  },
})

And make sure your resources/views/app.blade.php layout looks like this:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  @vite(['resources/js/app.js'])
</head>
<body>
  @inertia
</body>
</html>

Step 2: Create a File Upload Page with Vue.js

Let’s now create a Vue component for uploading files.

Create a new file at:
resources/js/Pages/FileUpload.vue

<template>
  <div class="max-w-md mx-auto mt-10">
    <h2 class="text-2xl font-bold mb-4">Upload File</h2>

    <form @submit.prevent="submitForm" enctype="multipart/form-data">
      <div class="mb-4">
        <input type="file" @change="handleFileChange" class="border p-2 w-full" />
        <div v-if="errors.file" class="text-red-600 mt-1">{{ errors.file }}</div>
      </div>

      <button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded">
        Upload
      </button>

      <div v-if="flash.success" class="mt-4 text-green-600">
        {{ flash.success }}
      </div>
    </form>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useForm, usePage } from '@inertiajs/vue3'

const file = ref(null)
const flash = usePage().props.flash
const errors = usePage().props.errors || {}

const form = useForm({
  file: null,
})

function handleFileChange(event) {
  form.file = event.target.files[0]
}

function submitForm() {
  form.post('/upload', {
    forceFormData: true, // Very important for file uploads
    onSuccess: () => {
      form.reset('file')
    }
  })
}
</script>

Step 3: Create a Route and Controller in Laravel

Create a route to handle the upload:

In routes/web.php:

use App\Http\Controllers\FileUploadController;

Route::get('/upload', function () {
    return Inertia\Inertia::render('FileUpload');
})->name('upload.form');

Route::post('/upload', [FileUploadController::class, 'store'])->name('upload.store');

Now create the controller:

php artisan make:controller FileUploadController

Inside app/Http/Controllers/FileUploadController.php:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class FileUploadController extends Controller
{
    public function store(Request $request)
    {
        $request->validate([
            'file' => 'required|file|max:2048|mimes:jpg,jpeg,png,pdf,docx'
        ]);

        $file = $request->file('file');

        $filePath = $file->store('uploads', 'public');

        return redirect()->back()->with('success', 'File uploaded successfully!');
    }
}

This controller:

  • Validates that a file is uploaded and checks its size and type
  • Stores the file under storage/app/public/uploads
  • Redirects back with a flash success message

Step 4: Set Up Storage Link

To make uploaded files publicly accessible, link the storage folder:

php artisan storage:link

Uploaded files will now be stored under public/storage/uploads.

You can access them like:

http://localhost:8000/storage/uploads/filename.ext

Step 5: Customize Validation Messages (Optional)

To customize validation messages, modify the request or handle them in the Vue component by accessing errors.file.

You already did this in the Vue form with:

<div v-if="errors.file" class="text-red-600 mt-1">{{ errors.file }}</div>

Step 6: Display Uploaded Files (Optional Enhancement)

If you want to display a list of uploaded files on the page:

Update your controller:

public function index()
{
    $files = Storage::disk('public')->files('uploads');

    return Inertia::render('FileUpload', [
        'files' => $files
    ]);
}

Then display them in the Vue component:

<template>
  <!-- ... existing form ... -->
  <div class="mt-6">
    <h3 class="text-lg font-semibold mb-2">Uploaded Files</h3>
    <ul>
      <li v-for="file in files" :key="file">
        <a :href="`/storage/${file}`" target="_blank" class="text-blue-600 underline">
          {{ file.split('/').pop() }}
        </a>
      </li>
    </ul>
  </div>
</template>

<script setup>
const props = defineProps(['files'])
</script>

Now you have a functional file upload page with a list of uploaded files.


Final Thoughts and Best Practices

  • Always validate file uploads to prevent malicious uploads.
  • Use forceFormData: true in Inertia when uploading files—this ensures files are sent properly.
  • Store files on a proper disk (public, s3, etc.) depending on your environment.
  • Limit file types and size with validation rules to improve security and performance.
  • Clean up old files if users replace or delete them over time.

Conclusion

Uploading files with Laravel 12, Inertia.js, and Vue.js is straightforward when you use Inertia’s form helper and Laravel’s powerful file storage system. With just a few lines of code, you can handle validation, storage, and even display uploaded files.

By using the modern Laravel-Inertia-Vue stack, you benefit from SPA-like interactivity while still leveraging server-side capabilities, such as file storage, validation, and routing—all without needing a separate API layer.



Leave a Reply

Your email address will not be published. Required fields are marked *