---
title: "Image variants — Media Library for Laravel | Roundly"
description: "Declare resized/reformatted derivatives that generate automatically; control sizing, format, quality and disk."
url: https://roundly-consulting.com/open-source/docs/media-library-for-laravel/image-variants
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Media Library for Laravel](https://roundly-consulting.com/open-source/docs/media-library-for-laravel.md)

# Image variants

Declare resized or reformatted image derivatives inline on a bucket — they are generated automatically whenever image media is added:

```php
$this->addMediaBucket('photos')
    ->useDisk('public')
    ->storingVariantsOnDisk('cdn')               // variants can live on a different disk
    ->registerVariants(function (VariantRegistrar $v): void {
        $v->add('thumb')->fit('crop')->width(120)->height(120)->format('webp');
        $v->add('display')->width(800)->format('webp')->quality(80)->queued();
        $v->add('hero')->fit('cover')->width(1600)->height(600)->sharpen(2);
    });
```

## Variant options

- Sizing — width(), height() and fit() with contain, cover/crop, fill (padded with background()) and stretch.
- Format — format() accepts jpg, png, webp, avif, gif (subject to the active driver).
- Quality / look — quality(1..100), background('#ffffff'), sharpen(int).
- Storage — storeOnDisk() for a per-variant disk override.
- Execution — queued() / nonQueued() per variant.

## Reading variants

```php
$media = MediaLibrary::for($user)->first('photos');

$media->getUrl('thumb');             // public URL of the generated variant
$media->getPath('display');          // path on the variants disk
$media->diskFor('thumb');            // the disk the variant was written to
$media->hasGeneratedVariant('thumb');
```

Each generated variant is recorded in generated\_variants with the file name, format and disk it was actually written to, and every URL, path, stream, move, copy and delete resolves that record:

```php
$media->generated_variants;
// ['thumb' => ['file_name' => 'thumb.webp', 'format' => 'webp', 'disk' => 'hot']]
```

A variant without its own format() inherits the original’s (IMG\_0001.JPG → keepformat.jpg; a format the drivers can’t write, such as .bmp, becomes jpg). The variant disk is resolved by precedence — the variant’s storeOnDisk(), the add’s storingVariantsOnDisk(), the bucket’s storingVariantsOnDisk(), config('media.variants\_disk'), then the media’s own disk — and the disk each variant landed on is recorded, so getUrl(), diskFor() and deletes follow it.

## Inspecting and regenerating

MediaLibrary::variants($media) lists the applicable definitions, shows what is generated or missing, and re-renders on demand — only missing variants unless you force it:

```php
$variants = MediaLibrary::variants($media);

$variants->all();                                   // list<Variant> — every definition that applies
$variants->generated();                             // ['thumb']
$variants->missing();                               // ['display']
$variants->regenerate();                            // render the missing ones → ['display']
$variants->regenerate(only: ['thumb'], force: true); // re-render thumb even though it exists

MediaLibrary::regenerate($media, only: ['thumb'], force: true); // the same verb, flat
```

## Drivers, queueing & events

Variants use ext-imagick by default and fall back to ext-gd; both auto-orient EXIF-rotated photos. They generate synchronously by default — opt into the queue per variant (->queued()), per add (->onQueue('media')) or globally via config('media.queue\_variants\_by\_default'). A queued GenerateVariantsJob is pushed only after the surrounding transaction commits (ShouldQueueAfterCommit), so a worker never looks for a row that isn’t there yet. VariantHasBeenGenerated fires per variant and VariantsHaveBeenGenerated once an add’s variants are all done. getUrl() only knows the variants a bucket declares: asking for a name the bucket never defined, or one not generated yet, throws InvalidVariant unless config('media.url\_fallback\_to\_original') is true — guard optional names with hasGeneratedVariant().

A variant that fails to render during an add, draft bind, attach, move, copy or replace — an image the driver can’t decode, a disk that refuses the write — is reported to your exception handler and skipped: the other variants still render and the call succeeds with the media stored. An explicit regenerate() throws instead, so check MediaLibrary::variants($media)->missing() rather than catching the add’s exception.

## What gets decoded

Both built-in drivers clear a file before they decode anything:

- Raster types only — JPEG, PNG, GIF, WebP, AVIF, BMP, TIFF, HEIC/HEIF and ICO, sniffed from the bytes; Imagick reads each through that type’s explicit coder, so a file never picks its own decoder. SVG is never decoded (an SVG can reference other files on the server): SVG media gets no variants and no placeholders, and regenerate() renders nothing for it.
- A pixel cap — width × height is read from the header without decoding, and an image over media.max\_image\_pixels (50,000,000 by default) is still stored, with no variants and no placeholders; an explicit regenerate() throws InvalidVariant. GD decodes inside PHP’s memory\_limit (roughly 5 bytes per pixel), so lower the cap on GD hosts with a small limit.
- The first frame only — Imagick reads frame 0 of an animation or a multi-page TIFF, so a variant of an animated GIF is its first frame, as with GD.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/media-library-for-laravel.md)
