File Uploads & Storage
Let users upload images and documents — validate them, store them safely on a disk, and show them back.
What you will learn
- Build an upload form and validate the file
- Store a file with the Storage facade
- Display the stored file to the user
How file uploads work
A file upload lets a user pick a file on their device (a profile photo, a PDF) and send it to your server. Two things make uploads different from normal form fields: the form needs a special encoding, and you must decide where the file is saved on the server. Laravel handles both cleanly with disks — named storage locations (local folder, public folder, or a cloud service like Amazon S3) configured in config/filesystems.php.
Step 1 — the upload form
An upload form needs enctype="multipart/form-data" — without it the file is not actually sent. The input uses type="file":
<form action="/products" method="POST" enctype="multipart/form-data">
@csrf
<input type="text" name="name">
<input type="file" name="photo">
<button type="submit">Save</button>
</form>Two details matter here. enctype="multipart/form-data" tells the browser to package the file properly for sending. <input type="file" name="photo"> is the file picker, and its name="photo" is how the controller will find the uploaded file. The @csrf token is required as on any POST form.
Step 2 — validate, then store
In the controller you first validate the file (is it really an image? not too big?), then store it. The store() method saves the file and returns the path it chose:
public function store(Request $request)
{
$request->validate([
'photo' => 'required|image|max:2048', // image, max 2 MB (2048 KB)
]);
$path = $request->file('photo')->store('products', 'public');
// e.g. $path is "products/3f9a...e1.jpg"
Product::create([
'name' => $request->input('name'),
'photo' => $path, // save the path in the database
]);
return redirect('/products');
}Walking through it: the rule 'required|image|max:2048' means the file must be present, must be an image, and must be at most 2048 KB (2 MB). $request->file('photo') grabs the uploaded file by its input name. ->store('products', 'public') saves it into a products folder on the public disk and returns a unique path like products/3f9a...e1.jpg (Laravel invents a random, safe filename so two uploads never clash). Crucially, you store the path string in the database, not the file itself.
Note: Output:
The image is saved to storage/app/public/products/3f9a...e1.jpg, and the photo column holds "products/3f9a...e1.jpg". Run php artisan storage:link once so the public disk is reachable from the web.
Step 3 — show the file
To display a stored public file, turn its saved path into a URL with the asset('storage/...') helper:
<!-- in a Blade view -->
<img src="{{ asset('storage/' . $product->photo) }}" alt="{{ $product->name }}">The saved path was products/3f9a...e1.jpg. Prefixing it with storage/ and passing it to asset() produces a full web URL like http://yoursite/storage/products/3f9a...e1.jpg, which the <img> then displays. (The storage:link command you ran is what makes that /storage URL point at your stored files.)
The full upload journey, in order:
- The user picks a file in a form that has
enctype="multipart/form-data"and submits. - The controller validates the file with rules like
imageandmax:2048. - You call
$request->file('photo')->store('products', 'public'), which saves it and returns a unique path. - You save that path (not the file) in the database column.
- To show it, build a URL with
asset('storage/' . $path)in a Blade<img>.
Watch out: Always validate uploads (image/mimes and max). Never trust the original filename — letting store() generate the name avoids overwrites and blocks dangerous filenames. For private files (invoices, ID documents) use the local disk instead of public so they are not web-accessible.
Q. After $request->file('photo')->store('products', 'public'), what should you save in the database?
✍️ Practice
- Build an upload form with
enctype="multipart/form-data"and validate the file as an image. - Store it on the public disk, save the path, and show it back with
asset().
🏠 Homework
- Add an avatar upload to a user profile: validate, store on the public disk, save the path, and display the avatar on the profile page.