Handling File Uploads: A Laravel Beginner's Guide
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.
Understanding Laravel Storage
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.
Step 1: Linking the Storage Directory
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.
Handling File Uploads in the Controller
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!'); }
Breaking down the code:
- Validation: We use
image|mimes:jpeg,png,jpg|max:2048to 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 instorage/app/public/tasks, and returns the relative path (e.g.,tasks/abc123xyz.jpg).- Database: We only save the string path, not the file itself.
Hands-on Exercise: Attaching Images to Tasks
- Update your
tasksmigration to include a nullable string column:$table->string('attachment_path')->nullable();. - Run
php artisan migrate. - In your
create.blade.phpform, add<input type="file" name="attachment">and ensure your form tag hasenctype="multipart/form-data". - Update your
TasksControllerto handle the file upload as shown in the example above. - In your
index.blade.php, display the image:<img src="{{ asset('storage/' . $task->attachment_path) }}">.
Common Pitfalls
- Forgetting
enctype: If your file is missing from the$request, check your HTML form tag. It is the #1 cause of "file not found" errors. - Permissions: Ensure your
storagefolder is writable by the web server. If you get permission errors, check your local environment's folder ownership. - Over-relying on
store(): Whilestore()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.
Recap
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.
Work with me

Laravel REST API Development
Clean, secure, well-documented Laravel REST APIs — the backend engine for your app, mobile client, or SaaS. Built by an API specialist.

FilamentPHP Admin Panel & Dashboard Development
A powerful admin panel for your Laravel app — built with FilamentPHP so you can manage everything without touching the database.