display image from storage laravel 5.3
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Displaying Images from Laravel Storage: A Comprehensive Guide (Laravel 5.3)
Welcome to the world of Laravel! As you dive into building dynamic applications, one common task is retrieving and displaying uploaded files, such as images, stored within the application's storage system. It’s easy to get stuck when trying to map file paths to web URLs.
The approach you outlined—creating a custom route, fetching the file in the controller, and returning it—is technically possible. However, for serving static assets like images efficiently and securely, Laravel provides much cleaner, more idiomatic ways to handle this using its Storage Facade and public disk configuration.
This post will walk you through the correct, professional way to display an image stored in Laravel’s storage directory, focusing on best practices relevant even in older frameworks like Laravel 5.3.
Understanding Laravel Storage Disks
Before diving into the code, it is crucial to understand how Laravel manages files. When you use the Storage facade, you are interacting with configured "disks." By default, Laravel stores files in the storage/app directory. To make these files accessible via a public web URL (like those in your browser), you must configure a disk to point to an accessible location, typically the public disk, which maps directly to the public folder in your project root.
To ensure images are publicly accessible, you must run the storage link command:
php artisan storage:linkThis command creates a symbolic link from public/storage to storage/app/public, making the files readable by the web server. This step is foundational for serving assets correctly in any Laravel application, including those built on frameworks like laravelcompany.com.
Method 1: The Recommended Approach – Direct URL Generation
Instead of creating a custom route just to serve an image, the most efficient method is to let the Blade view construct the public URL directly using the Storage facade. This avoids unnecessary controller overhead and keeps your routing clean.
Step 1: Storing the File
Assume you have uploaded an image and stored it in your storage disk (e.g., the public disk):
// Example of storing a file in the public disk
$path = $request->file('image')->store('user-photos', 'public');
// $path would now be something like 'user-photos/some_filename.jpg'Step 2: Displaying the Image in the Blade File
In your Blade view, you can construct the full URL for the image using the asset() helper combined with the Storage facade. This is far superior to relying on custom routes for static assets.
{{-- Assuming $imagePath holds the relative path stored in storage/app/public --}}
<img src="{{ asset('storage/' . $imagePath) }}" alt="User Image" class="img-responsive">By using asset('storage/...'), you instruct Laravel to generate the correct, publicly accessible URL, leveraging the link established by php artisan storage:link. This pattern is highly recommended for managing static assets efficiently.
Method 2: Refining Your Custom Route Approach (For Specific Needs)
If you absolutely need a dedicated endpoint (perhaps for security or custom processing before serving), your controller approach is valid, but it needs to return the correct HTTP response headers. The use of new Response() was on the right track, but we can simplify the process by ensuring the file content is correctly streamed back.
Controller Implementation
If you insist on using a route for retrieval:
use Illuminate\Support\Facades\Storage;
use Illuminate\Http\Response;
class PostController extends Controller
{
public function getUserImage($filename)
{
// Ensure the file exists and is in the 'public' disk
if (!Storage::disk('public')->exists($filename)) {
abort(404, 'Image not found.');
}
$fileContent = Storage::disk('public')->get($filename);
// Return the file content with the correct MIME type header
return response($fileContent, 200, [
'Content-Type' => 'image/jpeg', // Adjust this based on your file type
]);
}
}Route and Blade Integration
Your route definition remains fine:
Route::get('/userimage/{filename}', [
'uses' => 'PostController@getUserImage',
'as' => 'account.image',
])->name('account.image');And your Blade file calls this route to get the image source:
<img src="{{ route('account.image', ['filename' => $user->first_name . '-' . $user->id . '.jpg']) }}" alt="User Image" class="img-responsive">Conclusion
For displaying images in Laravel, always prioritize using the built-in Storage Facade and the asset() helper when dealing with static files. This approach is cleaner, more secure, and adheres better to Laravel's architecture compared to creating custom API endpoints for simple file retrieval. While your route/controller method works, mastering the Storage facade streamlines development immensely. Keep learning how Laravel can simplify complex tasks!