laravel doesn't upload images on server
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Why Laravel Doesn't Upload Images on Server: A Deep Dive into File System Deployment
It is an incredibly common and frustrating experience for developers when deploying a Laravel application. You manage to upload files perfectly fine on your local machine, everything works flawlessly during development, but once you move the site to a live host, the file uploads seem to vanish, even though the records exist in your database. This usually points to a discrepancy between how the application expects files to be stored and how the server environment is configured.
This post will diagnose why this happens, analyze the configuration of filesystems.php, and provide the definitive solution for reliably handling file uploads in production environments.
Understanding Laravel's File Handling Mechanism
Laravel provides robust tools for managing file storage through its Filesystem abstraction layer. When you use methods like $request->file('imageName')->move(...), you are instructing Laravel to write a file to a specific location defined by your configuration.
Let’s look at the typical configuration snippet you provided:
// In config/filesystems.php
'default' => env('FILESYSTEM_DRIVER', 'local'),
disks' => [
'local' => [
'driver' => 'local',
'root' => public_path('images/'), // <-- This is the key configuration point
],
// ... other disks
],
The core issue often lies in how the root path interacts with the web server's execution context and file permissions on the hosting environment.
The Diagnosis: Local vs. Public Path Confusion
Your observation—that the host created a new public/images folder instead of using your existing directory structure (like public_html)—is highly indicative of a path resolution problem, often exacerbated by deployment methods or server configurations (like Apache or Nginx virtual hosts).
When you use paths like public_path('images/'), Laravel resolves this path relative to the application's root directory. However, when deploying, the physical location on the server matters immensely:
- Application Root: The folder where your Laravel application resides (e.g.,
/var/www/html/myapp). - Web Root: The directory that the web server is configured to serve files from (often
public_htmlor thepublicfolder).
If you are writing files into a location defined by public_path(), but the public-facing web root isn't set up correctly, the files remain physically stored in the application structure but are inaccessible or invisible through the web server’s path. Furthermore, file permissions (CHMOD settings) on the host often prevent Laravel's PHP process from writing to those directories if they aren't properly configured for the web server user.
The Solution: Adopting Laravel Storage Best Practices
Instead of relying solely on direct manipulation of public folder paths for general storage, the recommended, robust method in modern Laravel development is to use the dedicated storage disk. This separates application-specific files from publicly accessible files, which significantly improves security and deployment reliability.
Step 1: Update filesystems.php
Configure your setup to use the standard storage directory for uploads.
// In config/filesystems.php
'disks' => [
'local' => [
'driver' => 'local',
// Store all user-uploaded files here, outside of the web root if possible
'root' => storage_path('app/public'),
],
],
Step 2: Update Upload Logic
Modify your upload code to use the configured disk driver. This ensures that when you move files, Laravel handles the actual file system operations using its established paths, which are more resilient across different hosting environments.
// Sample of improved upload code
use Illuminate\Support\Facades\Storage;
if ($request->hasFile('imageOne')) {
$imageOne = $request->file('imageOne');
// Store the file in the 'public' disk, within a subdirectory
$path = $imageOne->store('images', 'public'); // Stores inside storage/app/public/images/
// Save the path to the database
$product->imageOne = $path;
}
Step 3: Create the Public Symlink (The Essential Step)
For these files to be accessible via a web URL (e.g., /images/my_file.jpg), you must create a symbolic link from your application's public storage directory into the web-accessible public folder. This is how Laravel ensures that only files explicitly intended for public access are served.
Run this command in your terminal:
php artisan storage:link
This command creates the necessary link, ensuring that anything stored within the designated storage paths is properly exposed through your web root without manually worrying about complex path structures on the host. Following these steps ensures that file uploads are handled consistently, regardless of where your application is deployed, aligning perfectly with the principles advocated by the Laravel team at laravelcompany.com.
Conclusion
The problem you faced is a classic example of deployment environment mismatch rather than a bug in the core upload logic itself. By shifting from direct manipulation of public_path() to leveraging Laravel's official storage disk and using the storage:link command, you adopt a scalable pattern that protects your application against hosting inconsistencies. Always prioritize using the framework’s built-in tools for file management when deploying applications.