How to Optimize Images in Laravel
Resize, crop, and encode uploads with Laravel’s Image API, choose formats and quality deliberately, and move heavy processing to queues when needed.
Use Laravel’s fluent Image API, powered by Intervention Image, to resize or crop an image, encode it in a suitable format, and store the result on a Laravel filesystem disk. Install the package and a supported GD or Imagick PHP extension, choose output dimensions and quality for the image’s actual use, and queue large transformations when synchronous processing would make uploads slow or memory-intensive. Laravel’s API and installation details are in the Laravel image manipulation documentation.
1. Install and configure image processing
Laravel’s documented setup uses Intervention Image v4. Add the package with Composer:
composer require intervention/image:^4.0
Install and enable either the GD or Imagick PHP extension in every environment that will process images. Pick a driver supported by your deployment and confirm the PHP runtime can load it. The exact setup varies by operating system and hosting environment, so check the PHP extension configuration used by the web workers and queue workers, not only the CLI.
For current package and driver configuration, follow Laravel’s Image API documentation. Intervention’s format support matrix explains that supported formats depend on how GD or Imagick was built. Do not assume that a format available on a laptop is available in production.
2. Resize, encode, and store an image
This example reads an uploaded avatar, crops it to fill a square, encodes it as WebP at quality 80, and stores it publicly:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Image;
class AvatarController
{
public function store(Request $request)
{
$validated = $request->validate([
'avatar' => ['required', 'image', 'max:10240'],
]);
$path = Image::read($validated['avatar'])
->cover(400, 400)
->toWebp()
->quality(80)
->storePublicly('avatars', 'public');
return response()->json(['path' => $path], 201);
}
}
The validation rule and maximum size are application choices; set limits that match your upload policy. Laravel documents the fluent transformation and storage APIs. If your workflow starts with an image already on a disk, a documented pattern is:
use Illuminate\Support\Facades\Image;
$path = Image::fromStorage('avatars/photo.jpg', 'public')
->cover(400, 400)
->toWebp()
->quality(80)
->storePublicly('avatars', 'public');
3. Choose dimensions, format, and quality
| Decision | How to choose |
|---|---|
| Dimensions | Match the rendered slot. Use a thumbnail size for cards rather than serving an original photograph everywhere. Use cover when the output must fill fixed dimensions; choose a fit or resize operation that preserves the entire image when cropping would remove important content. |
| Format | WebP or AVIF may reduce file size for suitable content, while JPEG, PNG, GIF, and BMP are also among the documented encoders. Consider transparency, animation, consumers, and browser or application requirements before converting. |
| Quality | Use quality() to set an encoder quality from 1 to 100. The right value depends on image content and acceptable artifacts; inspect representative photos, graphics, gradients, and text-heavy images at their displayed size. |
| Existing assets | Decide whether to transform on upload, on demand, or in a background job. Avoid repeatedly re-encoding an already lossy output when the original is available. |
Laravel’s optimize() helper defaults to WebP at quality 70 and also accepts an output format and quality; its documentation shows JPEG at quality 85. Those are API defaults and examples, not universal best settings or guaranteed file-size reductions. Check transparency and output appearance, and verify the requested encoder exists in the production GD or Imagick build.
4. Process large images in a queue
Decoding, resizing, and encoding large images can consume substantial CPU and memory. Laravel recommends considering queued jobs for larger workloads instead of doing all transformation work during the upload request. There is no universal size threshold: consider input dimensions, concurrent uploads, worker resources, and the response time your application needs.
A common flow is to validate and store the original, dispatch a job with its disk and path, then have the job create the derivative and update the database when processing succeeds. Make the job safe to retry: write output to a deterministic destination or clean up partial output, and avoid creating duplicate records on repeated attempts. Keep originals if your product needs reprocessing at different sizes or formats.
5. Optimize existing files with command-line tools
If you need to optimize existing files without implementing resize and encode rules in application code, Spatie Laravel Image Optimizer is an alternative. Its Laravel integration invokes available command-line optimizers and covers PNG, JPG, SVG, and GIF workflows. The underlying tools can include utilities such as JpegOptim, Optipng, Pngquant, SVGO, Gifsicle, cwebp, and avifenc. Behavior depends on which binaries are installed and discoverable in the runtime.
See the Laravel package documentation and the underlying optimizer project. This approach is distinct from resizing or cropping with Laravel’s Image API. Check package compatibility and install the binaries in the same environment that executes the optimization, including queue workers if jobs perform it.
6. Troubleshooting
| Symptom | Likely cause | What to check or change |
|---|---|---|
| Driver or extension error | GD or Imagick is missing, disabled, or unavailable to the PHP process. | Check the extension in the web and worker PHP runtimes; install or enable the selected driver and restart the relevant processes. |
| Unsupported output format | The installed GD or Imagick build lacks the requested encoder. | Check the deployed runtime’s format support and choose an available format or deploy a build with the required capability. |
| Image looks soft or has artifacts | Output dimensions or quality are too low for the content and display size. | Increase dimensions or quality, compare the result at its real rendered size, and use a format appropriate for photographs or sharp graphics. |
| Transparent areas become opaque or look wrong | The target format or encoder path does not preserve transparency as expected. | Use a transparency-capable output and verify the result with representative assets and the deployed encoder. |
| Upload request is slow or runs out of memory | Large source dimensions or expensive transformations are processed synchronously. | Move work to a queue, limit accepted upload sizes and dimensions, and ensure workers have suitable resource limits. |
| Optimizer package does nothing or fails | Its external binaries are absent, not on the executable path, or unavailable to the worker user. | Install the required tools in the execution environment and verify permissions and paths for the actual process user. |
| Local output differs from production | PHP extension builds or installed optimizer binaries differ between environments. | Align runtime dependencies and verify the formats and tools in deployment before enabling that output path. |
7. Performance, reliability, and cost
- Performance: Resize to the needed dimensions early so downstream pages do not repeatedly download oversized originals. Benchmark with your own images and concurrency; the cited documentation provides no universal performance figures.
- Reliability: Test transformations in the same PHP and extension environment used in production. For queued work, handle retries and failures and make output writes safe to repeat.
- Storage and bandwidth: Derivatives consume storage, while appropriately sized files can reduce bytes served. Keep only variants your product uses, and decide whether originals must remain available.
- Cost: Account for PHP worker CPU and memory, queue capacity, storage, and bandwidth. External optimizer chains also require installing and maintaining their binaries. No fixed savings can be inferred without measuring your image mix and infrastructure.
Or skip the browser setup
Image optimization in Laravel concerns uploaded or stored image assets. If your application also needs screenshots of web pages, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns an image or PDF; its docs cover the API options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
- Cookie banners, newsletter popups, and chat widgets are removed before capture; each cleanup step can be turned off.
- Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers report the page verdict and billing status.
- An MCP server gives AI agents tools to take screenshots, inspect page information, and capture PDFs.
- 1,000 screenshots a month are free with no card. Paid plans start at $5 for 3,000 shots, and every feature is on every plan.
Sign up for 1,000 free screenshots a month, with no card required.
FAQ
Does image optimization always make a file smaller?
No. The result depends on source format, content, dimensions, encoder, and quality. Compare the encoded output with the original and check its appearance.
Should I convert every upload to WebP?
Not automatically. Check transparency, animation, consumer compatibility, and runtime encoder support before selecting a format policy.
Can I use Laravel’s Image API and Spatie’s optimizer together?
They serve different roles: the Image API handles transformations and storage, while the Spatie integration invokes available optimizer binaries. A pipeline can use both when needed, but avoid unnecessary repeated lossy encoding.


