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 External Image Laravel Package

chaseconey/nova-external-image

Laravel Nova field for displaying external images from remote URLs in your admin panel. Store image links on your models and render previews directly in Nova resources, with no local uploads or file storage required. Supports configurable sizing and display options.

View on GitHub
Deep Wiki
Context7

Getting Started

Confirm prerequisites before anything else: a working Laravel Nova installation (Nova is a paid, private Composer package, so this cannot be prototyped in a vanilla Laravel app) plus PHP/Laravel/Nova versions that fall inside the package's composer.json constraints. The package last shipped in December 2023, so open composer.json and the README first and compare against your Nova major before assuming it installs cleanly.

composer require chaseconey/nova-external-image

Then read the field class in vendor/chaseconey/nova-external-image/src (it is small — minutes, not hours) to confirm two things you will need immediately: the fully-qualified class name to import, and the $component string it registers, because that name must match a built Vue component in the package's dist/ assets. Verify it against your Nova version's field API.

Minimal usage — one absolute-URL column, rendered on index and detail:

use Chaseconey\NovaExternalImage\ExternalImage; // confirm FQCN from package source
use Laravel\Nova\Http\Requests\NovaRequest;

public function fields(NovaRequest $request)
{
    return [
        ID::make()->sortable(),
        Text::make('Name', 'name'),

        ExternalImage::make('Avatar', 'avatar_url')
            ->onlyOnIndex()
            ->onlyOnDetail(),
    ];
}

The column must already contain an absolute URL (https://cdn.example.com/…). The first use case worth piloting is exactly this: an OAuth/Gravatar avatar, a DAM/PIM asset URL, or a CDN-hosted logo on a resource you already have — ideally a non-critical admin screen. Do the first run in staging, open browser devtools on the index view, and confirm the requests go out and come back 200 before adding the field anywhere else.

Implementation Patterns

Split display from editing. The field is presentation-only — it does not upload, store, or transform. Keep a form-editable input next to it and make the image field display-only:

ExternalImage::make('Image', 'image_url')
    ->exceptOnForms()
    ->width(80)
    ->height(80),

URL::make('Image URL', 'image_url')
    ->onlyOnForms()
    ->rules('nullable', 'url'),

Compute or default the URL in resolveUsing. This is the clean seam for placeholders, CDN base concatenation, or deriving a URL from a stored path:

ExternalImage::make('Image', 'image_url')
    ->resolveUsing(fn ($value) => $value ?: asset('img/placeholder.png'))
    ->exceptOnForms(),

Prefer an accessor over mutating data. If the URL is assembled from parts (bucket + key, CDN host + filename), expose getImageUrlAttribute() on the model and point the field at that virtual attribute, so the field never becomes the place where URL logic lives.

Standardize sizing once. Because the field extends Nova's Image field, the familiar size helpers carry over — but don't set disk()/path() and expect storage semantics. Wrap field construction in a small trait or a static factory on a base resource so every screen renders the same dimensions and fallback, which is the actual consistency win of adopting the package over hand-rolled markup.

Fit it to reviewer workflows. Merchandising dashboards, moderation queues, catalog review, and CMS previews are the sweet spot: operators need to see the remote asset without re-uploading it. Keep these resources read-heavy and the field display-only.

Skip it for anything that isn't "show a remote URL." Uploads, resizing, signed/expiring URLs, caching, responsive variants, and alt-text enforcement are out of scope. Use Nova's Image/File fields for uploads; use a tiny custom field if you need fallback states or accessibility attributes baked in.

Testing. A Nova field is not meaningfully unit-testable here; a feature test asserting the resource endpoint returns the field component in its JSON payload is enough to catch a silently broken registration.

Gotchas and Tips

The inherited delete path is the real trap. The field extends Nova's Image, whose delete logic assumes a disk-relative path. Against an absolute URL, Storage::disk(...)->delete(...) silently no-ops. Either keep the field off forms entirely (exceptOnForms()) and clear the URL through the paired URL/Text field, or override the delete behavior in a subclass. Do not expose a file-delete affordance and assume it works — verify it in staging.

Compatibility is the gating risk, not effort. Low adoption (28 stars, 0 dependents), a single maintainer, and a 2023 release mean no evidence of support for the current Nova line. Pin the version in composer.json, and add an explicit "does the external image field still render?" smoke test to your Nova and Laravel upgrade checklists. Nova fields can fail silently — the field shows up but the Vue component never mounts. If nothing renders, check the browser console for an unresolved component, then confirm the package assets were published/compiled for your Nova version.

Rendering is browser-side (<img src>), which moves the risks. There is no server-side fetch, so no SSRF from your app — but admin browsers make third-party requests. Expect CSP img-src violations, mixed-content blocks when your admin is HTTPS and the image host is HTTP, and hotlink protection returning 403. External hosts can also track your internal staff via referrer/IP; if that conflicts with policy, proxy thumbnails through your own host or don't adopt.

Broken URLs render as broken images. There is no built-in error state; resolveUsing with a local placeholder is the practical mitigation. Don't point the field at signed/expiring URLs without re-resolving at render time, or older rows will rot.

Index performance scales with row count. One external request per row, per page load. Prefer a CDN-provided thumbnail URL over the full-size asset, and be aware that slow origins degrade Nova page loads regardless of the package.

Know your exit before you need it. The source is small enough to vendor into app/Nova/Fields or nova-components/ in hours: subclass the field, override $component, and ship your own tiny Vue component with fallback, loading="lazy", and alt text. Decide now whether that fork is your fallback, and record the fully-qualified field class in one place so the swap is a one-line change per resource.

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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels