File Uploads & Laravel Storage
Laravel's Storage facade provides a unified API for file operations that works identically across local disk, S3, DigitalOcean Spaces, and other drivers — change the driver in config/filesystems.php without touching your application code. Files are stored in storage/app/ and made web-accessible via a symbolic link (php artisan storage:link) to public/storage.
File Upload Flow
// Form with file upload (enctype is critical!)
<form method="POST" action="{{ route('posts.store') }}" enctype="multipart/form-data">
@csrf
<input type="file" name="image" accept="image/*">
<button>Upload</button>
</form>
// Controller handling
public function store(Request $request)
{
$request->validate(['image' => 'required|image|max:2048']);
// Store file (returns path like 'images/abc123.jpg')
$path = $request->file('image')->store('images', 'public');
// Store with custom filename
$path = $request->file('image')->storeAs(
'images',
'post-' . time() . '.' . $request->file('image')->extension(),
'public'
);
// Save path to database
Post::create([
'title' => $request->title,
'image_path' => $path,
]);
}
// Display the image (create symlink first: php artisan storage:link)
<img src="{{ asset('storage/' . $post->image_path) }}" alt="">
// Delete a file
Storage::disk('public')->delete($post->image_path);File Upload Best Practices
- Always validate file type and size before storing: 'image' => 'required|image|mimes:jpg,jpeg,png,webp|max:2048'. The mimes rule checks the actual MIME type, not just the extension — users can't rename a PHP file to .jpg
- Delete old files when updating: if ($post->image_path) { Storage::disk('public')->delete($post->image_path); } before storing the new file. Orphaned files waste server space
- Use store() not storeAs() unless you need a specific filename. store() generates a random unique filename that prevents collisions and exposes nothing about your storage structure
- For production, switch to S3 or a CDN. Change FILESYSTEM_DISK=s3 in .env and set AWS credentials — your application code stays identical
- Image processing: use the intervention/image package (composer require intervention/image) to resize images before storage: Image::make($file)->resize(800, null, function($c) { $c->aspectRatio(); })->save($path)
Tip
Tip
Practice File Uploads Laravel Storage in small, isolated examples before integrating into larger projects. Breaking concepts into small experiments builds genuine understanding faster than reading alone.
Laravel follows the MVC pattern with elegant routing and middleware
Practice Task
Note
Practice Task — (1) Write a working example of File Uploads Laravel Storage from scratch without looking at notes. (2) Modify it to handle an edge case (empty input, null value, or error state). (3) Share your solution in the Priygop community for feedback.
Quick Quiz
Common Mistake
Warning
A common mistake with File Uploads Laravel Storage is skipping edge case testing — empty inputs, null values, and unexpected data types. Always validate boundary conditions to write robust, production-ready laravel code.
Key Takeaways
- Laravel's Storage facade provides a unified API for file operations that works identically across local disk, S3, DigitalOcean Spaces, and other drivers — change the driver in config/filesystems.
- Always validate file type and size before storing: 'image' => 'required|image|mimes:jpg,jpeg,png,webp|max:2048'. The mimes rule checks the actual MIME type, not just the extension — users can't rename a PHP file to .jpg
- Delete old files when updating: if ($post->image_path) { Storage::disk('public')->delete($post->image_path); } before storing the new file. Orphaned files waste server space
- Use store() not storeAs() unless you need a specific filename. store() generates a random unique filename that prevents collisions and exposes nothing about your storage structure