Reducing an uploaded image's storage footprint involves two genuinely separate operations — shrinking its pixel dimensions, and reducing its file size through compression quality — and Intervention Image handles both without needing separate libraries.
Installing Intervention Image
composer require intervention/image-laravel
Resizing dimensions on upload
use Intervention\Image\Laravel\Facades\Image;
public function store(Request $request)
{
$request->validate(['photo' => 'required|image|max:5120']);
$image = Image::read($request->file('photo'))
->resize(width: 1200, height: null); // null height preserves aspect ratio
$filename = 'photos/'.uniqid().'.jpg';
Storage::disk('public')->put($filename, (string) $image->toJpeg());
Photo::create(['path' => $filename]);
}
Passing null for one dimension while specifying the other keeps the image's original aspect ratio, avoiding a stretched or squashed result.
Reducing file size via compression quality
$image = Image::read($request->file('photo'))
->resize(width: 1200, height: null);
$compressed = $image->toJpeg(quality: 75); // 0-100, lower means smaller file, more compression artifacts
Storage::disk('public')->put($filename, (string) $compressed);
A quality setting around 70–80 typically reduces file size substantially with minimal visible quality loss for photographic content — going much lower starts introducing visible compression artifacts.
Generating a smaller thumbnail alongside the full-size version
$original = Image::read($request->file('photo'));
$full = (clone $original)->resize(width: 1200, height: null)->toJpeg(quality: 80);
$thumb = (clone $original)->resize(width: 300, height: null)->toJpeg(quality: 80);
Storage::disk('public')->put("photos/{$filename}", (string) $full);
Storage::disk('public')->put("photos/thumbs/{$filename}", (string) $thumb);
Cloning the original image object before each resize avoids one operation mutating the source that the next resize call also needs to start from.
Converting to WebP for further size reduction
$webp = Image::read($request->file('photo'))
->resize(width: 1200, height: null)
->toWebp(quality: 80);
Storage::disk('public')->put('photos/'.uniqid().'.webp', (string) $webp);
WebP typically produces meaningfully smaller files than JPEG at a comparable visual quality — worth using directly where browser support for the site's audience is a non-issue, or generating alongside a JPEG fallback via the element otherwise.
Why doing this at upload time, not just relying on CSS sizing, matters
Serving a 4000px-wide original and scaling it down with CSS still forces the browser to download the full original file size — resizing and compressing at upload time is what actually reduces bandwidth and improves page load time, not just the displayed dimensions.