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 Media Hub Laravel Package

outl1ne/nova-media-hub

A media library and file manager for Laravel Nova. Upload, organize, search, and attach images and files to your resources through a clean, centralized interface, keeping all your assets in one place and simplifying media handling across the admin panel.

View on GitHub
Deep Wiki
Context7

Getting Started

Verify the prerequisite before anything else. This is a Nova tool, not a standalone package. If laravel/nova isn't installed and licensed, stop reading. Open the package's composer.json at the tag you intend to use and read the require block — it pins a Nova major, a PHP floor, and a Laravel range. If your Nova major isn't listed, you're evaluating a fork, not a dependency.

Minimal install path

composer require outl1ne/nova-media-hub
php artisan vendor:publish --provider="Outl1ne\NovaMediaHub\NovaMediaHubServiceProvider"
php artisan migrate
php artisan storage:link   # only if you use the public disk

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

public function tools()
{
    return [
        new \Outl1ne\NovaMediaHub\NovaMediaHub(),
    ];
}

Verify the publish tags, provider FQN, and tool/field class names against the README and src/ — the docs are thin relative to the surface area. composer show outl1ne/nova-media-hub plus a browse of vendor/outl1ne/nova-media-hub/ is your fastest source of truth.

Where to look first, in order

  1. config/nova-media-hub.php after publishing. Disk, path prefix, accepted MIME types, max size, and image conversions all live here. Every argument you'll have later is really an argument about this file.
  2. The package migrations. Confirm whether it ships its own tables or wraps spatie/laravel-medialibrary directly — that single fact determines coexistence cost with anything you already have.
  3. src/Fields/. This is your integration point with Eloquent resources.
  4. The release tag's dist/ folder. Confirms whether compiled assets ship or your CI needs Node.

First use case: one hero image on one throwaway resource. Add the media field to a low-risk model's fields(), upload through the Nova UI to each disk you actually use (local, then S3), attach, save, reload, and render it on a public page through your own accessor. That loop — upload → attach → persist → resolve URL on the front end — is the entire value proposition. If any leg needs custom code you didn't plan for, you've found the real scope. Budget half a day; the deliverable is a written go/no-go, not a demo.

Implementation Patterns

Separate the admin layer from the delivery layer. The package owns upload, browse, crop, and the Nova field. It does not own public rendering — URLs, <picture> markup, CDN base paths, cache headers stay in your application code. Put one accessor on the model and never call package APIs from Blade:

// app/Models/Page.php
public function heroUrl(string $conversion = 'hero'): ?string
{
    $media = $this->heroMedia; // your resolution, not the package's
    return $media?->url($conversion);
}

When the package is replaced or upstream stalls, this method is the only thing you rewrite.

Standardize conversion names on day one. Pick a small vocabulary — thumb, card, hero, maybe og — declare it in config, and reference it via class constants or an enum. The failure mode is a per-feature free-for-all where every developer invents banner-large and nobody can prune the conversion set later. Conversions also fail silently in exactly one environment, so pin them during the spike.

Decide "one owner of media records" before your first commit. If you already use Spatie Medialibrary or hand-rolled upload fields, adding this creates two media models in one codebase. Either migrate fully, or confine the package to a new resource type and document the boundary. Do not let the two coexist indefinitely — orphan cleanup, deletion semantics, and backfill all become ambiguous.

Wrap access behind your own layer. A thin MediaService or a HasHeroImage trait exposing attachMedia(), heroUrl(), and mediaInUse() costs an hour and turns a fork-and-own decision from a refactor into a swap. It also gives you one place to instrument usage.

Treat the Nova field as selection only. Ordering, alt text, captions, per-record credits, and usage rights belong in your columns or a pivot you control. That's also the data you'd need if you ever swap the package — plus it's the only media metadata your front end can depend on safely.

Multi-tenancy is your problem, not the package's. Nova authorization is resource- and model-level; it will not scope folders per tenant. Enforce it with a global scope plus a per-tenant path prefix in the disk config, and test that a tenant can't reach another tenant's media by guessing an ID.

Backfill as an idempotent Artisan command, staged last. Write media:import-legacy, run in staging, assert record counts and URL resolution, then production. Keep legacy upload fields read-only for at least one release cycle as a fallback. This is the one irreversible step in adoption.

Testing pattern. Storage::fake() in feature tests, upload a fixture through the field's save path, assert the URL resolves from your accessor — not from the package's internals. Testing the package's own behavior is wasted effort; testing your boundary is not.

Pair naturally with Nova Page Manager if you're already in that ecosystem — the shared-library-plus-field model maps cleanly onto page-builder workflows. This is also the most common reason teams end up here in the first place.

Gotchas and Tips

Nova upgrades break on the maintainer's schedule, not yours. Pin the version, and put "review nova-media-hub changelog" on the calendar for every Nova major bump. With 46 stars and 0 dependents you are an early adopter: expect to read source and budget one engineer who can patch a fork. Write down an abandonment threshold (e.g. no Nova-compatible release across two Nova majors) before you need it.

Asset build surprises. If the release tag doesn't ship dist/, you need npm install && npm run prod inside vendor/outl1ne/nova-media-hub — fragile, and it won't survive composer install in CI. Check the tag contents; if assets aren't prebuilt, either commit a fork or add a deliberate post-install step.

Uploads fail for boring, non-package reasons. A 413 or a silent failure is almost always upload_max_filesize, post_max_size, nginx client_max_body_size, or a Livewire upload limit. Check the browser network tab first, then PHP config on every environment, including queue workers.

Conversions need GD or ImageMagick everywhere, and memory. Missing extensions on a queue worker produce jobs that fail long after the upload looked successful. Large images can exhaust memory during conversion. Confirm synchronous vs. queued conversion in the spike — synchronous crops on a 20MB hero will visibly stall the Nova UI.

Deletion has two failure modes; pick your defense. First: deleting a media record other rows still reference, leaving broken references. Second: an asset file lingering after its record is gone. Add an "is this in use?" guard before delete and schedule a cleanup command for orphans. Never assume cascade behavior — verify it.

Private disks mean URLs are not public. If you configure S3 or a non-public disk, url() may return a signed, expiring link. Decide deliberately: public bucket plus CDN, or signed route through your app. Don't discover this in production when cached HTML holds expired URLs.

Keep blob paths out of your own schema. Store the media ID, resolve path and URL at runtime. Writing media/2024/06/foo.jpg into your own columns welds you to the package's path convention and makes rollback a file migration.

Config cache is the classic Nova-tool debugging trap. After publishing or editing config, run php artisan config:clear (and optimize:clear in a deployed environment). A stale cached config explains a surprising share of "the disk setting isn't taking effect" reports.

Release cadence may be a false signal. The recorded last-release date looks anomalous — check changelog activity directly on the repo before treating "maintained" as established fact. Adopt it because it fits your Nova stack and you're willing to wrap it, not because it looks healthy.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource