Reader Stacks

Generating Multiple Image Thumbnail Sizes in Laravel

Creating several resized versions of an uploaded image on the fly with Intervention Image — a small thumbnail, a medium preview, and the original — and why doing this at upload time beats resizing on every request.

Generating Multiple Image Thumbnail Sizes in Laravel

Serving one giant original image everywhere it's displayed — a small avatar, a card thumbnail, a full detail view — wastes bandwidth and slows page loads. Generating a few fixed sizes at upload time, once, is more efficient than resizing on every request.

Generating multiple sizes at upload

use Intervention\Image\Laravel\Facades\Image;

public function store(Request $request)
{
    $request->validate(['photo' => ['required', 'image', 'max:10240']]);
    $file = $request->file('photo');
    $filename = uniqid().'.jpg';

    $sizes = [
        'thumb' => 150,
        'medium' => 600,
        'large' => 1200,
    ];

    foreach ($sizes as $label => $width) {
        $image = Image::read($file)->scaleDown(width: $width);
        Storage::disk('public')->put("images/{$label}/{$filename}", (string) $image->toJpeg(82));
    }

    // optionally also store the original
    Storage::disk('public')->putFileAs('images/original', $file, $filename);
}

scaleDown() resizes proportionally without ever upscaling past the original — if the source image is smaller than the requested width, it's left as-is rather than stretched and degraded.

Why generate at upload time, not on every request

Resizing on every request (a common shortcut with an image-manipulation URL parameter) means paying the CPU cost of resizing repeatedly for the same image, for every visitor. Generating the fixed set of sizes once at upload and storing them means every later request just serves a pre-made file — dramatically cheaper at any real traffic volume.

An alternative for high-traffic sites: on-demand with caching

For applications where the exact sizes needed aren't known in advance (responsive images at many breakpoints), an on-demand image resizing service (Glide, or a CDN-level image transformation service) that caches its output after the first request is often a better fit than pre-generating every possible size manually.

Storing the paths

Store the generated filename (or a base identifier) on the model rather than full paths — construct the actual URL for each size at display time using Storage::url(), so a later change to the storage disk or naming scheme doesn't require a data migration.

Topics: File Uploads & Media