
August 17, 2026
9 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
Slow pages kill conversions, and unoptimized uploads are usually the culprit. Implementing effective image optimization in Laravel with Spatie Media Library requires moving beyond simple storage to automated, queue-driven transformation pipelines that generate modern formats and responsive variants at upload time. This guide covers the exact configuration, model setup, and Blade integration patterns I use on production eCommerce and legal-tech platforms to ensure fast Core Web Vitals without manual intervention. For broader context on how these optimizations fit into a high-performance store, see my guide on building SEO-optimized ultra-fast e-commerce platforms with Laravel.
registerMediaConversions() method, enabling withResponsiveImages() for automatic srcset generation, and offloading processing to a queue worker. This pipeline transforms raw uploads into optimized WebP/AVIF variants and responsive sizes asynchronously, ensuring fast page loads without blocking user requests.How do you configure Spatie Media Library for automated image optimization?
The foundation of reliable image optimization in Laravel with Spatie Media Library is correct package configuration. In 2026, with Laravel 12.x and PHP 8.4 as the current stable stack, you should be running Spatie Media Library v11 or higher. The default configuration works for basic storage but fails at performance because it processes images synchronously during the HTTP request cycle.
Install and publish configuration
composer require "spatie/laravel-medialibrary:^11.0"
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="medialibrary-config"
php artisan migrate After publishing, open config/media-library.php. The most critical change for production systems is setting the queue connection. Never process images synchronously in a web request; a single 5MB upload can block the response for seconds.
// config/media-library.php
'queue_name' => 'media-conversions',
'queue_connection_name' => env('MEDIA_QUEUE_CONNECTION', 'redis'),
'image_optimizers' => [
Spatie\ImageOptimizer\Optimizers\Jpegoptim::class => [
'-m85', '--strip-all', '--all-progressive',
],
Spatie\ImageOptimizer\Optimizers\Pngquant::class => [
'--force', '--quality=85',
],
Spatie\ImageOptimizer\Optimizers\Cwebp::class => [
'-m 6', '-q 80',
],
], You must also install the underlying optimizer binaries on your server. On Ubuntu 24.04, which I use for most Nepal-based client deployments:
sudo apt update
sudo apt install jpegoptim optipng pngquant libavif-bin webp Without these system packages, Spatie silently skips lossless compression even though your PHP configuration looks correct. I have debugged this exact issue on multiple production servers where developers assumed the Composer package included the binaries.
What media conversions should you define for optimal Core Web Vitals?
Defining the right conversions directly impacts Largest Contentful Paint (LCP) and Cumulative Layout Shift (CLS). A common mistake I see when auditing sites is defining too many conversions or using arbitrary pixel values. Every conversion you define generates a physical file on disk and consumes queue worker time. Be intentional.
Model-level conversion registration
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
class Product extends Model implements HasMedia
{
use InteractsWithMedia;
public function registerMediaConversions(?Media $media = null): void
{
// Thumbnail for admin tables and cart previews
$this->addMediaConversion('thumb')
->width(300)
->height(300)
->sharpen(10)
->format('webp')
->performOnCollections('images');
// Main product display - constrained width, auto height
$this->addMediaConversion('product')
->width(800)
->height(null)
->format('webp')
->withResponsiveImages()
->performOnCollections('images');
// Hero/banner variant for featured products
$this->addMediaConversion('hero')
->width(1200)
->height(600)
->fit(\Spatie\Image\Manipulations::FIT_CROP, 1200, 600)
->format('webp')
->performOnCollections('featured');
}
} Key decisions in this configuration:
- Format targeting: Always specify
->format('webp')explicitly. While browsers support AVIF more broadly in 2026, WebP still offers better compatibility with older devices still in circulation in Nepal and South Asia. Generate AVIF only if your analytics confirm significant traffic from supporting browsers. - Responsive images: Call
withResponsiveImages()only on conversions used in content areas where viewport width varies. Do not enable it for fixed-size thumbnails or avatars — it generates unnecessary files. - Crop strategy: Use
FIT_CROPfor hero banners where aspect ratio must be exact. Use unconstrained height (null) for product images to preserve natural proportions and avoid CLS. - Collection scoping: Always use
performOnCollections()to prevent thumbnail generation on PDF documents or video files attached to the same model.
How do you render responsive images correctly in Blade templates?
Generating optimized files is only half the battle. If your Blade templates reference the wrong URLs or omit width/height attributes, you negate all performance gains. Proper rendering of image optimization in Laravel with Spatie Media Library requires disciplined markup.
Using the built-in img tag helper
<!-- Recommended: Automatic srcset, sizes, and dimensions -->
{{ $product->getFirstMedia('images')?->img('product')
->attributes(['class' => 'w-full h-auto rounded-lg', 'loading' => 'lazy']) }}
<!-- Manual control when needed -->
@php $media = $product->getFirstMedia('images'); @endphp
@if($media)
<img
src="{{ $media->getUrl('product') }}"
srcset="{{ $media->getSrcset('product') }}"
sizes="(max-width: 768px) 100vw, 800px"
width="{{ $media->getWidth('product') }}"
height="{{ $media->getHeight('product') }}"
alt="{{ $media->alt ?? $product->name }}"
loading="lazy"
decoding="async"
class="w-full h-auto rounded-lg"
>
@endif Critical details often missed:
- Always include width and height attributes. Even with responsive CSS, the browser needs intrinsic dimensions to reserve space before the image loads. Missing these is the #1 cause of CLS on Laravel sites I audit.
- Use meaningful alt text. Pull from the media object’s
altfield, falling back to the model’s name. This matters for accessibility and on-page SEO. For legal-tech portals like those I build for Nepal law firms, descriptive alt text on document previews improves both compliance and search visibility. - Set loading="lazy" on below-fold images. Never lazy-load above-the-fold LCP images. For product detail pages, the first product image should use
loading="eager"and include a<link rel="preload">in the head. - Use decoding="async". This prevents image decoding from blocking the main thread during initial paint.
When should you regenerate conversions after changing media settings?
Configuration changes inevitably happen mid-project. You add a new conversion, adjust dimensions, or switch from JPEG to WebP. Existing media files retain their old conversions unless you explicitly regenerate them. This is a frequent source of "it works locally but not in production" bugs.
Safe regeneration workflow
# Regenerate ALL conversions (full site rebuild)
php artisan media-library:regenerate
# Regenerate only specific conversion names
php artisan media-library:regenerate --only=product,thumb
# Regenerate for a specific model type
php artisan media-library:regenerate --model-type="App\Models\Product"
# Regenerate only missing conversions (safe incremental)
php artisan media-library:regenerate --only-missing
# Force regeneration including existing files
php artisan media-library:regenerate --force In practice, always start with --only-missing on production. Full regeneration on a site with thousands of media items can take hours and consume significant CPU/memory. Run it via your deployment pipeline or as a scheduled job during low-traffic periods, never during peak hours.
For projects deployed with Deployer 7 and GitLab CI — the setup I use for multiple sister sites sharing infrastructure — add regeneration as a post-deploy task gated behind a flag:
// deploy.php
task('media:regenerate', function () {
if (get('regenerate_media', false)) {
run('{{bin/php}} {{release_path}}/artisan media-library:regenerate --only-missing');
}
})->desc('Regenerate missing media conversions'); This prevents accidental full rebuilds on routine deploys while making intentional regeneration a single variable toggle.
How does Spatie Media Library compare to alternative image optimization approaches?
Spatie Media Library is not the only option. Understanding trade-offs helps you choose correctly for your project’s constraints.
| Criteria | Spatie Media Library | Intervention Image + Custom | Cloudinary / Imgix |
|---|---|---|---|
| Setup complexity | Moderate (package + system binaries) | High (build entire pipeline) | Low (API-only) |
| Ongoing cost | Server resources only (~NPR 2,000–5,000/mo VPS) | Server resources only | Usage-based ($29–$224+/mo USD) |
| Queue integration | Built-in, configurable | Manual implementation | N/A (processed on CDN edge) |
| Responsive images | Automatic srcset generation | Manual breakpoint logic | Automatic with URL params |
| Offline/local dev | Full functionality | Full functionality | Requires internet + API key |
| Data sovereignty | Files stay on your server | Files stay on your server | Files stored on vendor CDN |
| Best for | SME apps, legal-tech, Nepal-hosted sites | Simple single-purpose transforms | High-traffic global SaaS, media-heavy apps |
For most Nepal-based businesses and SME clients I work with, Spatie Media Library hits the sweet spot: no recurring USD costs, data stays local, and the feature set covers real production needs. Cloud services make sense only when traffic volume justifies the expense or when you need global edge caching that your own infrastructure cannot provide. If you are evaluating hosting options alongside this decision, review cloud hosting services in Nepal for local pricing context.
Implement Image Optimization in Laravel with Spatie Media Library Today
Effective image optimization in Laravel with Spatie Media Library comes down to three non-negotiable practices: always process conversions via queue workers, define only the conversions your templates actually use, and render with explicit dimensions plus responsive srcsets. Skip any of these and you leave performance on the table or introduce layout instability. Start with the configuration and model patterns shown above, verify your system binaries are installed, and test with --only-missing regeneration before touching production. If you need help implementing this on an existing Laravel application or want a technical audit of your current media pipeline, get in touch to discuss your project.

