Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Medialibrary Uploaders Laravel Package

backpack/medialibrary-uploaders

Adds Backpack for Laravel admin panel uploaders for Spatie's Laravel Media Library, so you can attach images and files to your models through Backpack's familiar form fields instead of building custom upload logic.

View on GitHub
Deep Wiki
Context7

Getting Started

Install both the package and its underlying dependency (Spatie Media Library), then publish Spatie's migration:

composer require backpack/medialibrary-uploaders spatie/laravel-medialibrary
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="medialibrary-migrations"
php artisan migrate
php artisan storage:link

Next, make the Eloquent model media-aware. This is required before any uploader will work — the package writes through Spatie, not through a column:

use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class Product extends Model implements HasMedia
{
    use InteractsWithMedia;

    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('photo')->singleFile();
        $this->addMediaCollection('gallery');
    }
}

Then swap the field in your CRUD controller. The package ships uploaders that mirror Backpack's built-in upload field types (image, upload, upload_multiple); confirm the exact field-type/uploader names in the README, since they are registered by the package's service provider and are the one thing you should verify against your Backpack major version:

$this->crud->addField([
    'name'  => 'photo',        // must match the media collection name
    'type'  => 'image',        // media-library-backed uploader
    'disk'  => 'public',
    'aspect_ratio' => 1,
]);

Where to look first: the README for the registered field types, then src/Uploaders in the package (it is small — read the whole thing in ten minutes), then config/media-library.php for disk, conversions and queue settings.

First use case: take an existing avatar column on User, move it to a avatar media collection, and confirm the create/update flow writes a media row instead of a string path.

Implementation Patterns

Single-file vs. multi-file collections. singleFile() is what you want for avatars, covers, and logos — re-uploading in Backpack replaces the previous media item automatically. Without it you accumulate versions silently, and getFirstMediaUrl() starts returning whatever sorted first.

Read through the model, not the field. The uploader is write-side only. Every consumer (API resources, Blade, Inertia props) should go through Spatie:

$product->getFirstMediaUrl('photo', 'thumb');
$product->getMedia('gallery')->map->getUrl();

If you have existing views reading $product->photo, add an accessor so you don't chase them all down:

public function getPhotoUrlAttribute(): ?string
{
    return $this->getFirstMediaUrl('photo', 'thumb') ?: null;
}

Conversions for the admin preview. Backpack's image preview renders whatever URL the field resolves. Register a small thumb conversion and point the field's preview at it; otherwise the list view downloads full-resolution originals on every row.

$this->addMediaConversion('thumb')->width(200)->height(200)->nonQueued();

Use nonQueued() for admin thumbnails, or users will see broken previews until a worker picks the job up.

Multiple uploads in one field. For galleries and attachments, a multi-file collection plus the multiple-upload field type is the straightforward path. Inside a repeatable/repeater field, keep the collection name static and let Spatie handle ordering — do not try to derive collection names from repeater indices.

Migration path off a column. Do it in a one-off command: read the old column, addMediaFromDisk(...)->toMediaCollection('photo'), keep the column read-only for a release, then drop it. Don't do this inside a migration unless you're comfortable with storage side effects in schema changes.

Disk strategy. Put originals on S3 and set 'disk' => 's3' on the field plus the matching disk in config/media-library.php. Conversions land next to the original unless you set a separate conversion disk — worth doing, since thumbnails are served far more often than originals.

Gotchas and Tips

  • Unregistered collection = hard failure. Spatie throws InvalidMediaCollection the moment an upload hits a collection you didn't declare in registerMediaCollections(). Register collections before wiring the field, and remember models using HasMedia via a trait in a parent class need the trait's method to be reachable.
  • The field name and the collection name are two different strings. They're easy to conflate because the examples use the same value. They are not required to match; if you rename one, uploads silently go to the wrong bucket.
  • No column means no fillable, no casts, no orderBy. Any leftover $model->photo string logic (sorting, search, CSV exports) breaks. Audit before swapping the field.
  • Mass deletion bypasses cleanup. Model::where(...)->delete() and raw queries skip model events, so media rows and files are orphaned. Use php artisan medialibrary:clean or delete per-model. This is the recurring production bug with medialibrary.
  • Queued conversions need a worker. In local dev with QUEUE_CONNECTION=sync everything looks fine; in production the thumbnails just never appear. Either run a worker or mark admin-critical conversions nonQueued().
  • Debugging checklist, in order: does the media table have a row? Is model_type the FQCN you expect (proxies/polymorphism bite here)? Is the file on the configured disk? Does storage:link exist for the public disk? That sequence resolves most issues in under a minute.
  • Extension point: subclass the shipped uploader and override its save/retrieve methods if you need custom naming, per-tenant paths, or post-upload processing. Keep that subclass in your app, not in vendor.
  • Pin the version and read the source. With 13 stars and zero dependents, this is a thin adapter over Spatie, not a battle-tested dependency — the risk surface is the wiring between Backpack's field lifecycle and Spatie's API, and that's exactly what a Backpack major bump changes. It's MIT, so a fork is a legitimate escape hatch. Test the create and update operations after any Backpack or medialibrary upgrade; the field's hydration path is where breakage shows up.
  • Validation still belongs to you. Configure accepted_mime_types/dimension rules explicitly; the uploader will happily accept whatever Spatie accepts, and 'mime_types' on the field alone won't cover the update path in every Backpack version.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib