Laravel File Upload: The Complete, Current Guide

Upload files in Laravel the right way – form setup, validation rules, store() with hashed names, public disk, multiple files, and common upload errors.

Using Laravel to upload a file

Last updated: July 2026 – verified on Laravel 11/12

File uploads in Laravel take three pieces: a form with the right encoding, validation, and the store() call. Here is the whole flow with the current best practices.

1. The form

<form action="{{ route('documents.store') }}" method="POST" enctype="multipart/form-data">
    @csrf
    <input type="file" name="document">
    @error('document') <p class="error">{{ $message }}</p> @enderror
    <button type="submit">Upload</button>
</form>

enctype="multipart/form-data" is the piece everyone forgets — without it $request->file() returns null.

2. Validate, then store

public function store(Request $request)
{
    $validated = $request->validate([
        'document' => ['required', 'file', 'mimes:pdf,docx,jpg,png', 'max:5120'], // max in KB
    ]);

    $path = $request->file('document')->store('documents', 'public');

    // $path => "documents/kJh2...x8.pdf" (hashed filename, collision-safe)
    return back()->with('status', 'Uploaded to ' . $path);
}

Key points: max:5120 is kilobytes (5 MB); store() generates a hashed filename automatically so users can’t overwrite each other’s files; the second argument picks the disk from config/filesystems.php.

To keep the original name, use storeAs() — but sanitize it:

$name = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
$path = $file->storeAs('documents', str($name)->slug() . '.' . $file->extension(), 'public');

3. Make public files reachable

php artisan storage:link

This symlinks public/storage to storage/app/public, so the file is served at:

<a href="{{ Storage::url($path) }}">Download</a>

4. Multiple files

<input type="file" name="attachments[]" multiple>
$request->validate(['attachments.*' => ['file', 'mimes:jpg,png', 'max:2048']]);

foreach ($request->file('attachments', []) as $file) {
    $file->store('attachments', 'public');
}

5. Errors you will hit

  • File is null / validation says required → missing enctype, or the file exceeds PHP’s own limits. Raise upload_max_filesize and post_max_size in php.ini above your Laravel max: rule.
  • 413 Request Entity Too Large → the web server, not Laravel: raise client_max_body_size in nginx.
  • File visible in storage/ but 404 in browser → you forgot php artisan storage:link, or the symlink didn’t survive deployment (re-run it in your deploy script).

For upload UIs with live progress and previews, Livewire handles the same flow reactively — see my Livewire dynamic form builder with file uploads.can then access the uploaded file at the generated URL.

Comments

comments