mwguerra/filemanager
A full-featured file manager for Laravel and Filament v5 with database or storage browsing, S3/MinIO support, drag-and-drop uploads, file previews, multi-selection, and configurable security permissions.
The package is a Filament 5 / Laravel 12 / Livewire 4 plugin, so the first real decision is whether your panel is already on that stack. If you're on Filament 4 / Laravel 11, you're pinned to the ^1.0 line and will hit API differences (notably ->actions() → ->recordActions() and ->bulkActions() → ->toolbarActions() on tables) when you eventually upgrade. Confirm composer show filament/filament and livewire/livewire before installing; a mismatch here is the most common reason people bounce off this package.
Minimal install:
composer require mwguerra/filemanager:"^2.0"
php artisan vendor:publish --tag=filemanager-config
php artisan migrate
php artisan filemanager:install
Then register the plugin — nothing renders without this step, and it's easy to forget because the pages appear "missing" rather than erroring:
use MWGuerra\FileManager\FileManagerPlugin;
public function panel(Panel $panel): Panel
{
return $panel->plugins([
FileManagerPlugin::make(),
]);
}
Where to look first: the publishable config/filemanager.php after vendor:publish — it holds the disk, upload limits, MIME allowlist, blocked extensions, and mode defaults. Read it before writing any panel code; half the "it doesn't work" cases are a wrong disk or a too-tight MIME list there. Second, visit /admin/file-manager (database mode, full CRUD) and /admin/file-system (storage mode, read-only browsing) to see the two modes side by side.
First use case: point storage mode at an S3/MinIO bucket and use it as an ops-facing file browser before you ever touch database mode. It requires no schema, no policies, no metadata model — just ->disk('s3')->target('uploads') — so it's the fastest way to validate credentials, signing, and preview rendering in your environment.
Pick the mode deliberately. Storage mode reads the filesystem directly and is read-only; database mode tracks files as Eloquent rows (FileSystemItem) with metadata, thumbnails, and full CRUD. A useful day-to-day split: database mode for user-uploaded assets that need metadata, relationships, and policy checks; storage mode for admin/devops browsing of bucket contents you don't want to index.
Expose only what you need. The default plugin registers all four components (FileManager page, FileSystem page, FileSystemItemResource, and a SchemaExample demo page). Ship-with-demo-pages is a footgun in production:
FileManagerPlugin::make()
->only([
\MWGuerra\FileManager\Filament\Pages\FileManager::class,
\MWGuerra\FileManager\Filament\Pages\FileSystem::class,
])
->withoutSchemaExample();
Embed in forms rather than linking out. This is where the package earns its keep in real apps — a product edit form that lets the user manage its gallery:
FileManagerEmbed::make()
->height('400px')
->disk('s3')
->target("products/{$this->record->id}")
->defaultViewMode('grid')
->compact(),
Both FileManagerEmbed and FileSystemEmbed accept closures on every setter, so tenant- or user-scoped paths are natural:
FileSystemEmbed::make()
->disk(fn () => filament()->getTenant()->storage_disk)
->target(fn () => "tenants/{$tenant->id}/media")
->sidebarRootLabel(fn () => $tenant->name . ' Files')
Centralize configuration in the panel provider. The fluent API beats the config file for anything panel-specific, and precedence is fluent > config > defaults. Use the panel-level sidebar labels as defaults and override per page:
FileManagerPlugin::make()
->panelSidebarRootLabel('Root')
->fileManagerSidebarRootLabel('Assets')
->fileManagerNavigation(icon: 'heroicon-o-folder', group: 'Content', sort: 1)
->fileSystemNavigation(icon: 'heroicon-o-server-stack', group: 'Content', sort: 2)
Authorize via policies, not config. Wrap the pages in your own canAccessPanel() / Gate checks on the panel and let Laravel Policies cover the FileSystemItem model. Since the package ships a FileSystemItemResource, model policies apply to it directly — that's cleaner than trying to gate through package config.
Treat FileSystemItemResource as the escape hatch. When you need bulk metadata editing, custom columns, or scoped queries over tracked files, subclass or reconfigure that resource rather than building your own CRUD over the same table.
$wire.entangle('...') instead of @entangle('...'); stale published views are a silent-breakage source after the v1→v2 upgrade.config/filemanager.php while diagnosing, then tighten it back — the security posture here (MIME checks, sanitization, blocked extensions) is a feature, so don't disable it permanently.FileSystemItem, not the request. Users will notice accented characters and spaces being rewritten.blade-icons/blade-heroicons, but if you're mixing icon sets, override explicitly with ->icons([...]) or ->icon(FileManagerIcon::Folder, 'tabler-folder'). ->noIcons() is handy for a minimal compact embed.Storage::disk('s3')->files() from tinker), (3) does the user pass the policy, (4) is the file passing MIME/extension rules. Almost every issue lands in one of those four buckets.vendor/mwguerra/filemanager/src — it's small enough to skim, and the Schemas/Components and Filament/Pages directories answer most customization questions faster than searching.FileSystemItem. Avoid forking published views unless you have to — that's the piece most likely to break on the next Filament minor.How can I help you explore Laravel packages today?