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.
Architecture fit. This is a Filament-panel plugin, not a framework-agnostic file abstraction. It only fits a stack that is already committed to Filament for its admin surface — the package registers pages (/admin/file-manager, /admin/file-system), a Filament Resource, and schema components directly into Panel::plugins(). For a Filament shop this is a natural fit; for anyone else it is a non-starter.
The dual-mode design is the core architectural decision a TPM must force:
| Mode | Source of truth | Operations | Implication |
|---|---|---|---|
| Database mode | file_system_items table + disk |
Full CRUD, metadata, thumbnails | Requires backfill, introduces drift risk |
| Storage mode | The disk itself | Browse/preview only (read-only) | Zero migration, but no management |
A critical clarification for stakeholders: this is a browser UI, not a media library. It does not appear to provide polymorphic model attachments, so it is not a drop-in replacement for Spatie Media Library or laravel-medialibrary. If the roadmap needs "attach files to Order/Product/User," this package solves the browsing half and leaves the relationship half unsolved.
Integration feasibility. Mechanically low-friction: composer require, publish config, php artisan migrate, php artisan filemanager:install, register the plugin. The fluent FileManagerPlugin API is well-considered — configuration precedence (fluent > config file > defaults) is explicit, and embed components (FileManagerEmbed, FileSystemEmbed) with closure-based dynamic values give the panel-configuration-in-one-place property that keeps PanelProvider diffs reviewable. Embedding in forms is the highest-value lever, because it lets the team deliver one governed upload surface instead of bespoke upload widgets per resource.
Technical risk. The dominant risk is not quality, it is version narrowness:
->actions() → ->recordActions(), @entangle → $wire.entangle). Treat every Filament/Livewire major as a forced migration of this package.finfo) vs client-declared MIME; path traversal (../) defenses on move/rename/target; double-extension and polyglot handling (SVG with embedded script, HTML masquerading as image); whether SVG is previewable at all; presigned URL TTL; and whether previews proxy through the app (bandwidth + SSRF exposure) or redirect to S3.Key questions before adoption.
Storage::files() pagination, or full recursion? S3 LIST is 1000-key paginated and billed per request.Stack fit. Gate adoption on a single hard check: Laravel 12 + Filament 5 + Livewire 4. If the platform is one major behind, the honest options are (a) defer this package and revisit after the next platform upgrade, (b) adopt ^1.0 on Filament 4/Laravel 11 and accept an already-legacy branch, or (c) build a thin internal browser on Flysystem and skip the dependency. Do not let a single admin feature drive a platform-wide major upgrade on its own merits.
Migration path. Two distinct paths, and they should be chosen deliberately rather than defaulted:
file_system_items. That backfill is the real migration work, not the composer require. Write it as an idempotent, re-runnable Artisan command that walks the disk, derives metadata, and skips known rows — because it will be run more than once.If an existing attachment system is in place, do not attempt a rip-and-replace in the same release. Run this package in front of the same disks alongside the incumbent and cut over per-feature.
Compatibility. Verify against the actual panel topology before committing: multi-panel setups, non-default guards, and Filament tenancy all interact with plugin page registration and navigation groups. The FileSystemItemResource registers a route into the admin panel, which is an extra attack surface to review against the existing authorization model. Confirm the icon fallback behavior (the package ships inline SVGs when blade-icons/blade-heroicons is absent) does not clash with the panel's icon set.
Sequencing.
FileSystemEmbed or FileManagerEmbed) into a single low-risk form. Ship behind a feature flag.Maintenance. Budget roughly 0.25 FTE of ongoing Laravel developer attention, concentrated in bursts at each Filament/Livewire major. The realistic posture is fork-ready: keep a shallow internal fork or a pinned commit, and be prepared to carry patches. Given 0 dependents, the team will be among the first to encounter regressions on new Filament releases — you are the canary, not the beneficiary of a crowd.
Support. No commercial support, no SLA, GitHub issues only. That is acceptable for an internal admin convenience feature; it is not acceptable for a customer-facing upload path without an internal owner named in the runbook.
Scaling. Two cost curves to model before rollout:
LIST operation billed per request and capped at 1000 keys per page. Deep or flat-with-many-files buckets will feel slow and show up on the bill. Validate against the real bucket shape, not a synthetic 10-file fixture.Failure modes. Rank by likelihood:
| Failure | Trigger | Blast radius | Mitigation |
|---|---|---|---|
| DB/disk drift | S3 lifecycle rules, direct uploads, manual bucket edits | Stale rows, broken previews, 404s | Scheduled reconcile command + orphan report |
| Credential/disk rotation | Key rotation, bucket rename | All previews and uploads fail | Config validation at boot; alert on storage exceptions |
| Upload rejection at PHP layer | upload_max_filesize / post_max_size / timeout |
Silent failures, poor UX | Align PHP + nginx limits; explicit error surfacing |
| S3 move/rename timeout | Large object copy+delete | Partial state, duplicate objects | Enforce size threshold; async job for large moves |
| Livewire/Filament minor bump | Dependency update | Component breakage in admin | Pin exact versions; upgrade in a branch with the spike test suite |
| Authorization gap | New page/resource registered without policy | Unauthorized file access | Policy test coverage; route inventory in CI |
Ramp-up. Low for a Filament-fluent developer — half a day to a working embed, one to two days including policy hardening and the malicious-file test pass. The non-obvious learning is the dual-mode mental model and the three-tier configuration precedence; write a short internal ADR capturing which mode is canonical for which use case, or the team will diverge within two sprints. The SchemaExample demo page is useful for exactly one thing — getting stakeholders to sign off on the UX in a staging environment before engineering commits — so use it for that and disable it everywhere else.
How can I help you explore Laravel packages today?