Laravel inertia multi-part form data

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Mastering Multi-Part Form Data in Laravel Inertia: Handling File Uploads Seamlessly

As a senior developer working with the Laravel ecosystem, we frequently encounter scenarios that test our understanding of HTTP requests and data serialization—especially when bridging modern frontend frameworks like Vue and Inertia.js with powerful backend systems like Laravel. One common hurdle is handling multi-part form data, specifically file uploads alongside standard text inputs.

If you are building a membership form requiring both textual information and an image upload, it’s natural to seek a solution. The issue you are facing—receiving null for the picture in your backend—is a classic symptom of misunderstanding how files are transmitted over HTTP. This post will walk you through the correct implementation steps using Laravel 8, Inertia.js, and Vue.js to handle file uploads robustly.

Understanding Multipart Data Transmission

When you upload a file via an HTML form, the data is not sent as simple text fields; it must be packaged in a specific format called multipart/form-data. This format allows the submission of both standard form fields (text, numbers) and binary file contents simultaneously.

For this to work correctly, two critical components must align:

  1. Frontend Setup: The HTML form must explicitly signal that it is sending multipart data using the enctype="multipart/form-data" attribute.
  2. Backend Handling: Laravel's request object must be configured to parse this specific content type and extract the file data correctly.

Step 1: Ensuring Correct Frontend Structure (HTML & Vue)

Your provided HTML structure is a good start, but we need to ensure the file input is correctly mapped for submission. The use of v-model in Vue binds the file object reference.

Reviewing the Form Snippet

The key lies in how you bind the file input:

<input type="file" class="custom-file-input" id="exampleInputFile" @input="form.picture">

This correctly binds the selected file to your Vue component's data structure (form.picture). When this form is submitted, if the surrounding <form> tag is missing the necessary encoding, or if Inertia doesn't handle the standard HTML form submission correctly for files, the data gets lost.

In a typical Inertia setup, when you use $inertia.post(), it handles the underlying request structure, but we must ensure the file field name matches what the backend expects.

Step 2: Implementing Robust Backend Handling in Laravel

The failure to receive the picture on the backend usually means the controller is expecting a simple string value rather than a file object. When dealing with files in Laravel, you must use the request()->file() method.

The Controller Implementation

Instead of trying to access $request->input('picture'), you need to specifically look for the file input using methods like file().

Here is how your controller logic should be structured:

// app/Http/Controllers/MemberController.php

use Illuminate\Http\Request;
use App\Models\MemberPost;

public function store(Request $request)
{
    // 1. Validate the incoming request first! This is crucial for file uploads.
    $request->validate([
        'picture' => 'required|file|max:2048', // Example validation for the file
        'firstname' => 'required|string',
        // ... other fields
    ]);

    try {
        // 2. Handle the file upload from the request object.
        // The key ('picture') must match the 'name' attribute of your <input type="file"> tag.
        $pictureFile = $request->file('picture');

        if ($pictureFile) {
            // Store the file on the disk (e.g., public storage or local disk)
            $path = $pictureFile->store('member_pictures');
            
            // Proceed to save other data, linking the path if necessary
            MemberPost::create([
                'firstname' => $request->input('firstname'),
                // ... other text fields
                'picture_path' => $path, // Store the file path in the database
            ]);

            return response()->json(['success' => 'Member created successfully']);
        } else {
            // Handle case where no file was uploaded (should be caught by validation)
            return response()->json(['error' => 'No picture provided'], 422);
        }

    } catch (\Exception $e) {
        // Log the error for debugging
        \Log::error("File upload failed: " . $e