Laravel 13.20 Introduces First-Party Image Processing
Laravel 13.20 added native image processing through the new Illuminate\Image component (PR #59276). Before this release, every resize or WebP conversion required wiring up a third-party package manually. Now the framework ships a fluent, immutable API that handles resizing, cropping, format conversion, quality control, effects, and storing results on any filesystem disk.
Setup
The GD and Imagick drivers are backed by Intervention Image v4, which is a suggested dependency. Install it with:
composer require intervention/image:^4.0
Laravel defaults to the GD driver. Switch to Imagick per-image or globally via the images.default config:
$image->usingImagick()->toBytes();
Creating an Image Instance
The new Request::image() method is the most convenient entry point for uploads:
$image = $request->image('avatar'); // ?Illuminate\Image\Image
For every other source, use the Image facade or Storage:
$image = Image::fromPath('/path/to/photo.jpg');
$image = Image::fromUrl('https://example.com/photo.jpg');
$image = Image::fromStorage('uploads/photo.jpg', 's3');
$image = Storage::disk('s3')->image('uploads/photo.jpg');
How the Pipeline Works
Every transformation returns a new Image instance and nothing is processed until you request output (store(), toBytes(), width(), etc.). This lets you branch a single base image into multiple variants without side effects:
$photo = Image::fromStorage('uploads/photo.jpg')->orient();
$thumbnail = $photo->cover(300, 300)->quality(60)->toWebp();
$display = $photo->scale(width: 1600)->quality(80)->toWebp();
$thumbnail->storeAs('photos', 'photo-thumb.webp', disk: 's3');
$display->storeAs('photos', 'photo-display.webp', disk: 's3');
Calling orient() first auto-rotates the image using EXIF data—essential for phone camera uploads.
Resizing Methods
| Method | Behaviour |
|---|---|
| cover($w, $h) | Resize and crop to exact dimensions |
| contain($w, $h, $bg) | Fit inside dimensions, pad with background |
| scale($w, $h) | Proportional resize, never upscales |
| resize($w, $h) | Force exact dimensions, may distort |
| crop($w, $h, $x, $y) | Cut a region at the given offset |
Formats, Quality, and optimize()
Convert to any common format with dedicated methods:
$image->toWebp()->quality(80);
$image->toAvif()->quality(70);
$image->toPng();
The optimize() shortcut converts to WebP at quality 70 by default:
$image->optimize(); // WebP @ 70
$image->optimize('avif', 60); // AVIF @ 60
Storing Results
$path = $image->store('avatars'); // hashed filename
$path = $image->storeAs('avatars', 'user-1.webp'); // explicit name
$path = $image->storePublicly('avatars', disk: 's3'); // public visibility
The hashed filename automatically uses the correct extension for the output format.
Practical Example: Avatar Upload Controller
public function update(Request $request)
{
$request->validate(['avatar' => ['required', 'image', 'max:5120']]);
$path = $request->image('avatar')
->orient()
->cover(512, 512)
->optimize()
->storePublicly('avatars', disk: 's3');
$request->user()->update(['avatar_path' => $path]);
return back();
}
Conditional Transformations
Image uses Laravel's Conditionable trait, so when() works as expected:
$image = $request->image('photo')
->when($request->boolean('grayscale'), fn ($img) => $img->grayscale())
->scale(width: 1200)
->optimize();
Key Takeaways
- No extra wiring:
Illuminate\Imageis built into Laravel 13.20; just install Intervention Image v4. - Immutable pipeline: transformations return new instances, making multi-variant generation safe and clean.
scale()never upscales: safe default for responsive image generation.optimize()is a one-call shortcut to WebP at quality 70.- Images cannot be serialized to queued jobs—store first, pass the path.
ImageExceptionis the single exception type for all processing failures.
Source: A Practical Guide to Laravel's First-Party Image Processing — Laravel News