Add the HasMedia contract and the InteractsWithMedia trait to any model, then declare its buckets in registerMediaBuckets():
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\MediaLibrary\Concerns\InteractsWithMedia;
use RoundlyConsulting\MediaLibrary\Contracts\HasMedia;
use RoundlyConsulting\MediaLibrary\Variants\VariantRegistrar;
final class User extends Model implements HasMedia
{
use InteractsWithMedia;
public function registerMediaBuckets(): void
{
$this->addMediaBucket('avatar')
->singleFile() // replaces the previous file on add
->acceptsMimeTypes(['image/jpeg', 'image/png', 'image/webp'])
->useDisk('cold') // originals on cold storage
->storingVariantsOnDisk('hot') // derivatives on hot storage
->private() // visibility: signed URLs only
->useFallbackUrl('https://example.com/avatar.png')
->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();
});
$this->addMediaBucket('gallery')->useDisk('public');
}
}Bucket builder
Each bucket is configured with a fluent builder:
$this->addMediaBucket('docs')
->singleFile() // keep only the latest file
->acceptsMimeTypes(['application/pdf'])
->useDisk('s3') // originals disk
->storingVariantsOnDisk('cdn') // variants disk
->public() // or ->private()
->useFallbackUrl('/img/doc.png') // returned by url() / getFirstMediaUrl() when empty
->responsiveWidths([480, 960, 1440])
->registerVariants(fn (VariantRegistrar $v) => $v->add('preview')->width(640));- singleFile() — keep only the latest file; adding replaces the previous one (MediaHasBeenDeleted fires for it).
- acceptsMimeTypes([...]) — restrict the bucket to a mime allowlist. A bucket without one accepts any type, HTML and SVG included — give every bucket that holds user uploads an allowlist.
- useDisk() / storingVariantsOnDisk() — pin originals and variants to specific disks.
- public() / private() — visibility; private media is served only through signed URLs.
- useFallbackUrl() — the URL returned by MediaLibrary::for($model)->url() (or getFirstMediaUrl()) when the bucket is empty.
- responsiveWidths() / registerVariants() — declare responsive widths and image variants.
- maxFileSize() / minDimensions() / maxDimensions() — constraints that also drive MediaLibrary::rulesFor().
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 cryptoBy donating, you agree to our donation terms.
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.