DEV Community

Md.Shariful Islam
Md.Shariful Islam

Posted on

5 levels of handling images in Laravel

Image uploads are a common feature in most web applications. In this post, we'll walk through how to implement image uploads in Laravel, starting from the basics and gradually moving toward a full-featured solution. We'll cover resizing, image optimization, and UI enhancements and show how Spatie's packages and products can make the whole process easier, more efficient, and even a bit fun.

Level 1: Plain Laravel and the basics of image uploads
Let's start with a minimal example of how you can handle image uploads in Laravel using built-in functionality—no packages, just core features.

  1. Set up the form First, you'll need a form in your Blade template that allows users to upload an image:
<form
    action="{{ route('upload') }}"
    method="POST"
    enctype="multipart/form-data"
>
    @csrf
    <input type="file" name="image">
    <button type="submit">Upload</button>
</form>
Enter fullscreen mode Exit fullscreen mode
  1. Handle the upload in a controller In your controller, you can handle the incoming file like this:
public function store(Request $request)
{
    $request->validate([
        'image' => 'required|image|max:2048', // max 2MB
    ]);

    $path = $request->file('image')->store('uploads', 'public');

    return back()
        ->with('success', 'Image uploaded successfully!')
        ->with('path', $path);
}
Enter fullscreen mode Exit fullscreen mode

What you get
✅ A working upload flow
✅ Basic validation (image file, max size)
✅ Storage in the public disk

What's missing?
❌ No resizing or manipulation
❌ No optimization for performance
❌ No UI enhancements or previews
❌ No support for attaching images to models (like users or posts)

Level 2: Adding spatie/image
Now that basic uploads are working, let's say you want to resize or crop images before saving them. Laravel doesn't offer built-in tools for this, but Spatie's image package gives you an elegant and straightforward way to manipulate images.

Using the image package, we can extend our controller to add some image resizing:

public function store(Request $request)
{
    $request->validate([
        'image' => 'required|image|max:2048',
    ]);

    $uploadedFile = $request->file('image');

    // Store the original temporarily
    $path = $uploadedFile->store('temp');

    // Define the final path
    $finalPath = 'uploads/' . $uploadedFile->hashName();

    // Resize and save
    Image::load(storage_path('app/' . $path))
        ->width(800)
        ->save(storage_path('app/public/' . $finalPath));

    // Optionally remove the original
    Storage::delete($path);

    return back()
        ->with('success', 'Image resized and uploaded!')
        ->with('path', $finalPath);
}
Enter fullscreen mode Exit fullscreen mode

Other things you can do
height(400) – constrain height
fit(800, 600) – resize to fit into a box
crop(width, height, x, y) – manually crop a section
blur(15) – apply blur
greyscale() – make the image black and white

What you get
✅ Image resizing and manipulation
✅ Clean, chainable syntax
✅ Works well for one-off or simple workflows

What's missing?
❌ No optimization (file size can still be large)
❌ Still manual—no model integration
❌ No UI integration

Next, let's fix the performance part by optimizing the images before we store them.

Level 3: Using spatie/image-optimizer to shrink file size
So far, we've got image uploads and resizing working, but the file size might still be much larger than it needs to be. Especially for web apps, keeping images small is critical for performance. That’s where spatie/image-optimizer comes in.

This package automatically optimizes images using well-known CLI tools under the hood (like jpegoptim, pngquant, and svgo)—without noticeably degrading quality.

Lucky for us image-optimizer seemlesly integrates with the image package so we only need to add one line to our controller:

public function store(Request $request)
{
    ...

    // Resize and save
    Image::load(storage_path('app/' . $path))
        ->width(800)
        ->optimize() // This will optimize the image before saving.
        ->save(storage_path('app/public/' . $finalPath));

    ...
}
Enter fullscreen mode Exit fullscreen mode

What you get
✅ Automatically smaller file sizes
✅ No visual quality loss
✅ Works with any image manipulation flow

What's missing?
❌ Still no model integration
❌ No UI integration

Level 4: Using spatie/laravel-medialibrary
Spatie's laravel-medialibrary is a powerful package that takes image uploads to the next level. It allows you to associate uploaded files (not just images!) with Eloquent models, generate automatic conversions, handle storage cleanly, and much more.

Installation
You can find the full installation instructions for laravel-media library.
Usage
Once installed, we can create a model, in this case a post, and simply attach our uploaded image to it:

public function store(Request $request)
{
    $request->validate([
        'title' => 'required',
        'image' => 'required|image|max:2048',
    ]);

    $post = Post::create([
        'title' => $request->input('title'),
    ]);

    $post->addMediaFromRequest('image')
         ->toMediaCollection('featured');

    return redirect()->back()
        ->with('success', 'Post created and image uploaded!');
}
Enter fullscreen mode Exit fullscreen mode

What you get
✅ Images are attached to models
✅ Automatic conversions (thumbs, responsive, etc.)
✅ Clean file storage
✅ Support for collections and multiple images

What's missing?
❌ No user-friendly upload UI
❌ Upload experience is still native HTML form elements (no previews, drag & drop)

Level 5: Using Media Library Pro for a polished UI uxperience
Once you've got laravel-medialibrary set up, Media Library Pro takes things to a whole new level. It's a commercial add-on by Spatie that provides drop-in Vue and Livewire components for a modern, user-friendly image upload experience—with previews, drag & drop, progress bars, reordering, and more.

💡 Media Library Pro is a paid product, but it will save you hours of frontend work and integrates tightly with Laravel.

Media Library Pro is available for all types of frontend: Blade, Livewire, React and Vue. Installation instructions can be found in our extensive documentation.

Once installed, you can add the component to your frontend code. Here's a Blade example:

<form method="post">
    <x-media-library-attachment name= "image" rules= "mimes:png,jpeg,pdf"/>

    <button>Submit</button>
</form
Enter fullscreen mode Exit fullscreen mode

And in our controller you can handle the upload like this:

public function store(Request $request)
{
    $request->validate([
        'title' => 'required',
        'image' => 'required|image|max:2048',
    ]);

    $post = Post::create([
        'title' => $request->input('title'),
    ]);

    $post->addFromMediaLibraryRequest('image')
         ->toMediaCollection('featured');

    return redirect()->back()
        ->with('success', 'Post created and image uploaded!');
}
Enter fullscreen mode Exit fullscreen mode

Which should result in a beautiful, functional upload component:

Image description

What you get
✅ Modern, reactive UI components
✅ Deep integration with your models
✅ Preview, progress, reordering out of the box
✅ Built and maintained by the creators of Media Library

What's missing?
🙌 Nothing!

Conclusion
Whether you stick with Laravel's built-in tools or go all-in with Media Library Pro, how far you take your image upload implementation depends on your project's needs. The Spatie packages and products at every level offer well-crafted solutions to help you build a clean, efficient, and scalable solution.

Top comments (0)