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

Nova Filemanager Laravel Package

infinety-es/nova-filemanager

Infinety Nova File Manager brings a full-featured file browser to Laravel Nova. Manage files across multiple disks: upload, rename, move, delete, create folders, and preview images. Add FileManager fields to resources for easy media handling in Nova's admin panel.

View on GitHub
Deep Wiki
Context7

Getting Started

Decide the Nova version question before you type composer require. The last tagged release is 2.8.3 (2020-08-21) and it targets the Nova 2/3 asset pipeline (Mix manifest). Nova 4/5 uses Nova::script/Vite. If you are on Nova 4+, your first task is not "install the package", it is "prove the tool renders in a scratch app". Everything else in this assessment is contingent on that passing.

composer require infinety-es/nova-filemanager:2.8.3   # pin exact, not ^2.8
php artisan vendor:publish --provider="InfinetyEs\NovaFilemanager\ToolServiceProvider"
php artisan storage:link

Register the tool in app/Providers/NovaServiceProvider.php:

public function tools()
{
    return [
        (new \InfinetyEs\NovaFilemanager\Filemanager())
            ->canSee(fn ($request) => $request->user()->can('manage-media')),
    ];
}

Where to look first, in this order:

  1. config/nova-filemanager.php — disk name, root/folder path, rename/delete/upload permission flags. This is effectively the entire day-to-day configuration surface.
  2. php artisan route:list | grep filemanager — the nova-vendor/filemanager/... endpoints (list, upload, rename, delete, create-folder). You will debug against these with curl more than you expect, and they are also your integration point for an iframe picker.
  3. src/Filemanager.php — the tool class. Your subclassing hook for canSee(), display name, and per-domain scoping.
  4. resources/js/ — only when you accept that you are forking for Nova 4/5.

First use case to build: a dedicated media disk rooted at storage/app/public/media, exposed as one tool, with editors uploading blog images and PDFs. Store the relative path returned by the manager in a path column and resolve it with Storage::disk('media')->url($path). That is the 20 minutes of bespoke upload UI the package exists to save you.

Smoke test on day one, in this order: does the tool appear in the sidebar at all → does an uploaded file land on disk (ls storage/app/public/media) → do thumbnails resolve in the browser. Each failure points at a different layer (asset pipeline / disk config / symlink), and you want to know which one you are in before you wire it to a content model.

Implementation Patterns

Always use a dedicated disk. Never local, never the project root. Create a disk whose root is the folder you want exposed, so path traversal is prevented by the filesystem driver rather than by the package's validation:

// config/filesystems.php
'media' => [
    'driver'     => 'local',
    'root'       => storage_path('app/public/media'),
    'url'        => env('APP_URL').'/storage/media',
    'visibility' => 'public',
],

Then set 'disk' => 'media' in config/nova-filemanager.php. This single decision removes most of the security surface you would otherwise have to audit.

One tool instance per content domain. A single flat tree containing logos, invoices, and blog heroes is a UX failure that lands on you. Subclass the tool and scope the root per instance:

class BlogImages extends \InfinetyEs\NovaFilemanager\Filemanager
{
    public function __construct()
    {
        parent::__construct();
        config(['nova-filemanager.folder_path' => 'blog']);
    }

    public function canSee(NovaRequest $request): bool
    {
        return $request->user()->can('manage-blog-media');
    }
}

Register BlogImages and MarketingAssets separately. Two sidebar entries with distinct permissions beat one tool plus a hallway convention about which subfolder to use. Verify at boot that config is read when the tool renders, not cached at registration — this generation of Nova tools commonly reads a single global config, which is why the subclass sets it in the constructor.

canSee() hides; a policy enforces. Treat canSee() as UX only. The real capability check belongs in a gate/policy, and it must also be applied to anything you build around the same disk (a custom controller, an iframe picker route, an API endpoint).

Wrap referenced files in a Media model. Storing a raw path in posts.image works right up until an editor renames the file in the manager and your article silently loses its hero image. A Media model with disk, path, mime, size, uploaded_by gives you an audit trail, a referential check before deletion, and one place to resolve URLs:

Storage::disk($media->disk)->url($media->path);

Never string-concatenate URLs elsewhere. One helper, one source of truth.

Wire the picker into rich text editors. This is the practical reason many teams install the package: point a CKEditor/TinyMCE file-browser button at the nova-vendor/filemanager URL in an iframe dialog and legacy CMS content gets a working asset picker for free. Confirm the exact route name with route:list after registration — it has moved between releases — and pass your session cookie through when testing.

Handle S3 and multi-server deliberately. Listing and uploads go through Laravel's filesystem abstraction and generally work. Two things you must verify yourself: that url() yields signed URLs for a private bucket, and that rename/move code does not assume POSIX rename() semantics S3 does not have. On ephemeral containers (Vapor, Forge zero-downtime deploys) never leave the default local root in place — it disappears on redeploy and takes the media with it.

Back up and prune out of band. There is no trash can and no versioning. A nightly snapshot of the media disk plus a scheduled command purging an incoming/ folder older than N days covers both failure modes: accidental deletion and abandoned uploads. Schedule this the same day you install, not after the first incident.

Constrain deletion for editor roles. Either flip the delete flag off in config for non-admins, or route deletion through your own action that checks the Media model for references first. The package's delete is permanent and immediate.

Gotchas and Tips

  • Config is cached. php artisan config:clear after editing nova-filemanager.php. This is the number one "the package is broken" false alarm — your disk change silently didn't apply.
  • Run php artisan storage:link. "Uploads succeed but images 404" is almost always the missing symlink. Check it before you debug anything else.
  • Three independent upload limits. PHP's upload_max_filesize/post_max_size, Nginx's client_max_body_size, and any WAF in front. Blowing any of them surfaces in Nova as a generic 500 or 419 rather than a friendly validation message, so a "random" failure on large files is usually one of these three, not the package.
  • Nova 4/5 asset registration is the classic failure mode for abandoned Nova tools. The tool mounts but renders a blank panel because the compiled JS isn't loaded. Fix by publishing assets manually and adding Nova::script('nova-filemanager', __DIR__.'/../vendor/infinety-es/nova-filemanager/dist/js/tool.js') in NovaServiceProvider, or fork and rebuild against Vite. Budget a day.
  • Filesystem ownership. www-data needs write access to the disk root. chown -R www-data:www-data storage/app/public/media clears the opaque 500s that appear after deploying as a different user.
  • Case sensitivity mismatch. macOS is case-insensitive, Linux is not. A team creates Hero.jpg locally and hero.jpg in production, then gets duplicates or silent overwrites. Enforce lowercase-on-upload if the content model keys off filenames.
  • Per-user and per-tenant scoping is not built in. For multi-tenancy, subclass the tool and derive the root from $request->user()->tenant_id. Do this before the first customer is onboarded; retrofitting it after tenants have shared a disk is a data-migration problem, not a config change.
  • Extension allow-lists are your only upload guard. Restrict extensions in config and make sure the disk is not web-executable — serve media through a controller or keep the root outside the document root. A .php file uploaded into a served directory is a remote shell.
  • Debugging workflow that actually works: when the UI misbehaves, hit the nova-vendor/filemanager endpoints directly with curl plus your session cookie. Clean separation between "frontend broken" (asset pipeline) and "backend broken" (permissions, disk config, routes). Two completely different fixes.
  • Pin an exact version and treat upgrades as migrations. "infinety-es/nova-filemanager": "2.8.3", never a caret range. Never patch vendor/ — fork into your own namespace so the change shows up in code review and survives composer install.
  • Extension points that cover most requests without touching internals: subclass Filemanager for scoping/display names/permissions; publish and edit views to change the toolbar; add middleware to the nova group for IP allow-listing the whole admin panel.

The package is a time-boxed convenience layer, not a platform bet. Point it at a dedicated disk, wrap paths in a Media model, gate it with a policy, back up nightly, and you get a working file manager for the cost of an afternoon — on Nova 2/3. On Nova 4/5, the afternoon is the spike, and the day is the fork.

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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings