Learn how to handle file uploads in Laravel, configure local storage, and manage file paths effectively to store user-provided content in your application.
Previously in this course, we explored introduction to database relationships in Laravel to associate our tasks with specific categories or users. Now that we can manage relational data, it's time to add media capabilities to our Task Manager by learning how to handle file uploads.
In web development, you rarely want to store files directly in your database; instead, you store the file on the server (or a cloud provider) and save the file's path as a string in your database. Laravel makes this workflow incredibly simple through its unified filesystem abstraction.
Laravel provides a robust Storage facade that acts as a wrapper around the underlying filesystem. Whether you are storing files on your local machine, an Amazon S3 bucket, or an FTP server, the API remains the same.
By default, Laravel is configured to use the local disk. However, if you want files to be accessible via a web browser (like user-uploaded profile pictures or task attachments), you need to store them in a directory that the web server can serve, such as storage/app/public.
The storage/app/public directory is not automatically accessible to the public web browser because it sits outside the public/ folder for security reasons. To expose it, we create a symbolic link (symlink) from public/storage to storage/app/public. Run this command in your terminal:
Bashphp artisan storage:link
This command creates a shortcut so that any file uploaded to storage/app/public can be accessed via your-app.test/storage/filename.jpg.
To accept files, your HTML form must include the enctype="multipart/form-data" attribute. Without this, the browser will not send the file binary data to your server.
In your controller, you can access the uploaded file via the Request object. Here is a concrete example of how to store an attachment for a task:
PHPpublic function store(Request $request) { #6A9955">// 1. Validate the file $request->validate([ 'attachment' => 'required|image|mimes:jpeg,png,jpg|max:2048', ]); #6A9955">// 2. Store the file and retrieve the path #6A9955">// This saves the file to storage/app/public/tasks $path = $request->file('attachment')->store('tasks', 'public'); #6A9955">// 3. Save the path to your database model Task::create([ 'title' => $request->title, 'attachment_path' => $path, ]); return back()->with('success', 'Task created with attachment!'); }
image|mimes:jpeg,png,jpg|max:2048 to ensure users only upload valid images under 2MB. This is a critical step to secure file uploads from the ground up.store('tasks', 'public'): This method automatically generates a unique filename, places the file in storage/app/public/tasks, and returns the relative path (e.g., tasks/abc123xyz.jpg).tasks migration to include a nullable string column: $table->string('attachment_path')->nullable();.php artisan migrate.create.blade.php form, add <input type="file" name="attachment"> and ensure your form tag has enctype="multipart/form-data".TasksController to handle the file upload as shown in the example above.index.blade.php, display the image: <img src="{{ asset('storage/' . $task->attachment_path) }}">.enctype: If your file is missing from the $request, check your HTML form tag. It is the #1 cause of "file not found" errors.storage folder is writable by the web server. If you get permission errors, check your local environment's folder ownership.store(): While store() is great, for complex apps, you might need more control. If you encounter issues, look into mastering Laravel storage: a beginner’s guide to file uploads for advanced techniques like manual file naming.We've successfully bridged the gap between user input and server-side storage. By linking our storage directory, validating file types, and using the store() method, we can now handle media attachments reliably. Remember: always validate the file type and size to keep your application secure and performant.
Up next: We will learn how to provide immediate feedback to users using Flash Messages after their file uploads are successful.
Master Laravel storage for file uploads with this practical guide. Learn how to handle local and cloud files using the filesystem facade efficiently.
Read moreStop the N+1 query problem in its tracks. Learn how to use eager loading in Laravel to keep your application fast and efficient as your data grows.
Handling File Uploads
Debugging with Laravel Tinker
Understanding Service Providers
Using View Composers
Task Manager: Refactoring for Clean Code
Introduction to Testing
Testing Forms and Validation
Using Database Transactions
Handling Global Exceptions
Preparing for Production
Environment Security Best Practices
Managing Assets in Production
Task Manager: Deployment Preparation