buglinjo/laravel-webp
buglinjo/laravel-webp is a Laravel package for converting JPEG and PNG images to WebP, helping you serve smaller, faster-loading images. It offers a simple facade and API for saving, quality tuning, and cleanup, making WebP optimization easy in any Laravel app.
This release (v3.2.0) only widens framework constraints to allow Laravel 13.x — there are no API changes, so upgrades from v3.1.0 are a composer update buglinjo/laravel-webp away. Confirm the resolved version and that illuminate/support now accepts ^13.0 before you rely on it in CI.
First steps:
composer require buglinjo/laravel-webp and publish the config: php artisan vendor:publish --provider="Buglinjo\LaravelWebp\LaravelWebpServiceProvider" (or --tag=webp). The file lands at config/webp.php and holds the default quality (90) plus the underlying image driver settings.php -r "var_dump(gd_info()['WebP Support']);". A missing encoder is the single most common cause of "it works locally, breaks in prod".use Buglinjo\LaravelWebp\Facades\Webp;
$path = $request->file('photo')->store('uploads', 'public');
Webp::make(Storage::disk('public')->path($path))
->quality(80)
->save(Storage::disk('public')->path('uploads/photo.webp'));
Look first at the package's Webp class (the facade root) and the config file — that's the entire public surface. Everything else is Intervention Image underneath.
Upload pipeline in a controller. Keep conversions out of the request cycle when files are large: store() the original, dispatch a job with the path (not the UploadedFile), convert there, and delete the original on success.
Preserving the source. make($file)->save($dest) consumes the conversion and removes the original; saveAsCopy($dest) keeps both. Reach for saveAsCopy() whenever the original is still referenced elsewhere (thumbnails, reprocessing, audits).
Deterministic filenames. Generate Str::slug(pathinfo($name, PATHINFO_FILENAME)).'-'.Str::random(8).'.webp' and store the mapping, or hash the source (md5_file) and cache the conversion. Re-converting the same image on every request is the usual performance trap.
Serving with fallback. WebP is broadly supported but don't hardcode it in templates:
<picture>
<source srcset="{{ $webpUrl }}" type="image/webp">
<img src="{{ $originalUrl }}" alt="">
</picture>
Also set the right content type at the web-server/CDN layer — a .webp served as image/jpeg will break some clients.
Chained configuration. Quality is per-instance, so tune per context rather than globally: hero images at 85–90, thumbnails at 70–75, and treat the config default as a floor for convenience.
Testing. Because conversion shells out to the image driver, assert on outcomes (file exists, getimagesize() reports IMAGETYPE_WEBP, size decreased) rather than byte-exact fixtures — encoder output varies across GD/Imagick versions.
save() deletes the original. The most frequent surprise. If you lost a file in dev, that's why.Storage::path() / Storage::disk()->path() is the bridge; passing a disk-relative key fails silently or throws from the driver.orientate()/rotate before converting or portrait photos arrive sideways.UploadedFile temp paths are deleted at request end. Pass a stored path and re-hydrate inside the job.$e->getMessage() with the filename — you'll otherwise only notice broken images from user reports.config/webp.php, run php artisan config:clear (and remember config:cache in deploy scripts freezes the old values).How can I help you explore Laravel packages today?