Laravel 12 Display Image From Storage Folder

In this laravel tutorial you will learn how to display image stored in laravel’s storage folder with step by step example.

When working with file uploads in Laravel, one of the most common tasks is displaying images stored in the storage folder. In this tutorial, we’ll walk through the step-by-step process of uploading and displaying images from the storage directory in a Laravel 12 application.

Laravel 12 Storage Architecture

Laravel organizes file storage into different disks, each serving specific purposes:

  • Local disk: Stores files in storage/app directory (private by default)
  • Public disk: Stores files in storage/app/public directory (intended for web-accessible files)
  • S3 disk: Stores files in Amazon S3 cloud storage

The key distinction is that files in the public disk are meant to be accessible via web URLs, while files on the local disk remain private unless explicitly served through controllers.

By default, images uploaded using the public disk are stored in the storage/app/public directory.

To make these images accessible publicly, run this command:

php artisan storage:link

This creates a symbolic link(shortcut) inside your public/storage folder that points to the storage/app/public directory. Laravel does not copy or duplicate files.

  • Files are really saved in storage/app/public/
  • A shortcut (symlink) is created at public/storage/
  • When you access /storage/images/photo.jpg, Laravel redirects it to /storage/app/public/images/photo.jpg
storage/app/public/ Folder Preview
storage/app/public/ Folder Preview
Laravel 12 Display Image From Storage Folder
symbolic link(shortcut) inside your public/storage folder that points to the storage/app/public

Step 1: Store Images on Public Disk

When uploading files, specify the public disk:

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use App\Models\User;
 
class UserController extends Controller
{ 
 
 public function store(Request $request)
    {       
          
           $request->validate([ 'image' => 'required|mimes:jpg,png,jpeg',]);
             
           // Saving an uploaded image 
           $imagePath = $request->file('image')->store('images','public');
            
           //Save path to database
            auth()->user()->update(['avatar'=>$imagePath]);    

            return back()->with('success','Image Uploaded Successfully!');
    }
} 
    

Step 2: Display Images Using Storage Facade

Retrieve image URL in controller, Use Laravel’s storage Facade generate proper image URLs. The Storage::url() method automatically generates the correct URL path that maps through the symbolic link.

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use App\Models\User;
 
class UserController extends Controller
{  
 

public function displayImage()
    {       
         
        $imageUrl = Storage::url('images/9FOxDeLj1oTMOuEpInT2sZSj4RsJQ0QNTFkboCcz.png');
        return view('post',compact('imageUrl'));
    }

}

Display image in blade view (Using Controller Variable)

<img class="mb-3 image_gallery" src=" {{asset($imageUrl)}}" id="image_gallery">
  • $imageUrl comes from the controller.
  • asset() converts it to a full public URL (e.g., https://yourapp.com/storage/images/…).

Directly Use Storage Facade in Blade

You can directly display image using Storage facade in blade template :

<img src="{{ Storage::url('images/photo.jpg') }}" alt="Photo" class="img-fluid">

This is simpler if the filename is known.

Use Public Asset Path

If your image is already available in the public/storage folder, you can also reference it directly:

<img class="mb-3 image_gallery" src=" {{asset('storage/images/photo.png')}}" id="image_gallery">

This works because asset(‘storage/…’) points to files inside public/storage.

Read Also : Laravel 12 Validation Rule Sometimes vs Nullable

Method 2: Secure Image Streaming Through Controllers

Step 1: Create Image Controller

For images requiring access control or enhanced security, stream them through dedicated controllers:

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use App\Models\User;
 
class UserController extends Controller
{  
 

public function displayImage($imageName)
    {     
        $path = 'images/'.$imageName;
        
        // Verify file exists
        if (!Storage::disk('public')->exists($path)) {
            abort(404, 'Image not found');
        }
         // Get file contents and MIME type
        $file = Storage::disk('public')->get($path);
        $type = Storage::mimeType($path);

        return response($file, 200)->header('Content-Type', $type);
    
    }
}

Inside this function, you build the file path (like images/photo.png), check whether the file exists using Storage::disk(‘public’)->exists(), and if it doesn’t, you return a 404 “Image not found” error. If the file does exist, you read its content using Storage::get() and also get its MIME type (like image/png or image/jpeg) with Storage::mimeType(). Finally, you return the image as a response with the correct content type header using Laravel’s response() helper.

Step 2: Define Secure Routes

You also define a route such as :

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;

Route::get('img/{imageName}', [UserController::class,'displayImage'])->name('img');

This route points to the controller method, and you can then use it in your Blade template to display the image :

<img src="{{ route('img', ['imageName' => 'photo.png']) }}" alt="User Photo">

This approach ensures complete access control while maintaining proper MIME type headers for browser compatibility.

Read Also : Laravel 12 Custom Validation Error Messages Example

Laravel 12 Display Image From Storage Folder

Common Issues

Image not showing?

Make sure you have created the symbolic link using: php artisan storage:link

Permission denied error?

Ensure your storage folder has the correct permissions: chmod -R 775 storage

Wrong path?

Always use asset(‘storage/’.$filename) instead of storage_path() when displaying images in Blade templates.

Conclusion

Laravel 12 offers multiple robust approaches for displaying images from storage folders. The symbolic link method works excellently for public images with optimal performance, while controller-based streaming provides superior security for sensitive content. Choose the approach that aligns with your application’s security requirements and performance needs.

Always implement proper file validationerror handling, and follow Laravel’s security best practices to ensure your image display functionality remains both functional and secure.


Frequently Asked Questions (FAQs)

Q1: Why can’t I access images directly from the storage folder?

By default, Laravel’s storage folder is not publicly accessible for security reasons. Files stored in storage/app/public can only be viewed on the web after creating a symbolic link using the command php artisan storage:link.

Q2: What is the difference between Storage::url() and asset() when displaying images?

Storage::url() automatically generates the correct file path based on your configured storage disk, while asset() simply converts a relative path to a full public URL. Both work, but Storage::url() is preferred when working with Laravel’s filesystem disks.

Q3: Which method should I use — symbolic link or controller streaming?

Use symbolic link method for normal, public images (like profile photos or blog thumbnails).
Use controller-based streaming for private or sensitive files that should only be visible to authorized users.

Q4: What are MIME types, and why are they important?

A MIME type (like image/png or image/jpeg) tells the browser how to interpret and display the file. When streaming images through a controller, setting the correct MIME type ensures that the browser can display the image properly.