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 File Manager Laravel Package

bbs-lab/nova-file-manager

A file manager for Laravel Nova that lets you browse, upload, organize, and manage files and folders directly inside your Nova admin panel. Provides a clean interface for common file operations, making media and document management easy without leaving Nova.

View on GitHub
Deep Wiki
Context7

Getting Started

The package slots into Nova as both a Tool (a full-page file browser under the sidebar) and a Field (an uploader you drop onto resource forms). You almost always want both.

  1. Install

    composer require bbs-lab/nova-file-manager
    
  2. Publish config and assets

    php artisan vendor:publish --provider="BbsLab\NovaFileManager\NovaFileManagerServiceProvider"
    

    You should end up with config/nova-file-manager.php and published JS/CSS under public/vendor/nova-file-manager. Publish assets again after every composer update — this is the single most common "it looks broken" cause.

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

    public function tools()
    {
        return [
            \BbsLab\NovaFileManager\NovaFileManager::make(),
        ];
    }
    
  4. Make storage reachable — the manager operates on a Laravel disk, so the disk must actually be browsable by the web process. For local disks:

    php artisan storage:link
    

    Then confirm the disk in config/filesystems.php matches the disk value in the package config.

  5. First use case: add the field to a model form and upload a cover image.

    use BbsLab\NovaFileManager\FileManager;
    
    public function fields(Request $request)
    {
        return [
            FileManager::make('Cover')->disk('public')->path('covers'),
        ];
    }
    

    The value stored is the relative path on the disk — treat it like any other string column and resolve URLs with Storage::disk('public')->url($model->cover).

Where to look first

  • config/nova-file-manager.php — disk, base path, allowed extensions, max size, preview behaviour. This is where 90% of "why can't I upload X" lives.
  • The README's field vs. tool examples — the two APIs differ (field is form-bound, tool is a browser) and the docs split them early.
  • The published config's disk/path keys before you touch any Vue or views.

Implementation Patterns

Tool as the shared media library. Register one tool with a broad base path (e.g. media) and let editors browse/reuse assets across resources. Keep the tool read-heavy and restricted by policy so it doesn't become a dumping ground.

Field per model, scoped path. Give each resource its own namespace so uploads don't collide:

FileManager::make('Gallery')
    ->disk('s3')
    ->path("models/{$this->resource->id}/gallery")
    ->multiple()
    ->acceptedTypes(['image/*']);

Storing under an ID-scoped path makes cleanup on delete trivial — hook Model::deleted and Storage::disk(...)->deleteDirectory(...).

Multi-disk in one app. Config the tool to a public disk for editor assets and point specific fields at S3/private disks. The field-level disk()/path() overrides the global config, so you rarely need multiple tool registrations.

Multi-tenancy. Derive the base path from the tenant rather than publishing a separate config per tenant: a small service provider or the field's path() closure reading tenant()->slug keeps tenant files isolated while reusing one tool.

Integration with rich-text editors. The tool exposes a browse/upload URL that TinyMCE/CKEditor file pickers can be pointed at. Wire the editor's file browser callback to the tool route so "Insert image" opens the Nova manager instead of a bare upload input — this is the highest-leverage integration for content teams.

Authorization. Don't rely on the tool's canSee alone if fields are also mounted. Add a Nova policy/gate check in the field's canSee/readonly closures so per-role upload restrictions hold everywhere.

Post-upload processing. Use the package's upload events (or a queued listener on file creation) to generate thumbnails, strip EXIF, or push to a CDN. Keep this in listeners, not in the field definition, so both tool and field uploads get the same treatment.

Testing. Point the test disk at Storage::fake('public') and assert the stored path rather than the rendered Vue component. For the UI, keep a couple of Dusk tests on the tool page only — the field is better covered by form-submission tests.

Gotchas and Tips

  • Assets go stale silently. After upgrades, re-publish and hard-refresh. A blank tool page with a 404 on vendor/nova-file-manager/js/... is almost always an unpublished asset, not a PHP error.
  • Disk visibility vs. previews. Private/S3 disks with visibility: private will upload fine but show broken previews. Either set visibility: public, or use signed/temporary URLs if the package config supports URL generation — check the config before assuming a bug.
  • PHP limits bite before the package does. Large uploads fail at upload_max_filesize/post_max_size/max_execution_time, not in Laravel. If chunked uploads are configured, verify the chunk endpoint is reachable behind your proxy (nginx body limits, load balancer timeouts).
  • Path traversal. Keep the configured base path strict and never build path() from raw user input. Validate that any dynamic path is inside the intended root; a permissive base path plus ../ is a real security issue, not just a cosmetic one.
  • Config cache. After editing config/nova-file-manager.php, run php artisan config:cache (or config:clear in dev). Nova also has its own cache — nova:clear if a newly registered tool doesn't appear.
  • Storage permissions. storage/app/public and the published vendor directory must be writable/readable by the web user. A 403 on thumbnails is usually ownership, not the package.
  • Field vs. tool confusion. Both live in the same namespace and share config keys. If a field ignores your disk() call, check you're not accidentally relying on the global tool config — field overrides are explicit.
  • Sorting/pagination surprises. Directory listings are read live; on S3 or network disks, large folders feel slow. Keep per-field paths narrow and avoid pointing the tool at a bucket root.
  • Extension allow-list over deny-list. Configure allowed extensions rather than blocking dangerous ones — SVGs and HTML uploads are stored XSS vectors if served from the same origin.
  • Debugging path: browser network tab on the tool's listing/upload requests → package log entries → Storage::disk(...)->allFiles($path) in tinker to confirm what's actually on disk. That sequence isolates "Nova problem vs. storage problem vs. package problem" in about two minutes.
  • Extension points worth knowing: custom disk drivers (register in filesystems.php, reference by name in config), overriding published views for tool chrome, and the upload events. Prefer these over forking — the package moves fast (last release mid-2025), and forks rot.
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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource