Reader Stacks

How to Compress and Resize Images on Upload in Laravel

Resizing an image's dimensions and reducing its file size via compression quality are two separate levers — Intervention Image handles both.

How to Compress and Resize Images on Upload in Laravel

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.