ahmedkandel/nova-s3-multipart-upload
Laravel Nova field for uploading large files directly to Amazon S3 via multipart uploads. Chunked uploads improve reliability and performance for big assets, integrating cleanly into Nova resources and forms.
Scope note: this assessment is derived from the v2.0.0 release note ("Add support for Nova v4, PR #26"). No prior assessment exists; the package is a Laravel Nova extension (tool/card/field/filter-style component) whose only documented v2.0.0 change is Nova 4 compatibility.
Verify the version matrix before touching code
v2.0.0 targets Nova 4. If your app is still on Nova 3, stay on the 1.x line — the major bump is the signal that the Nova 3 code path is no longer supported.composer.json for constraints on laravel/nova, laravel/framework, and php. Nova 4 itself requires PHP 8.0+ and a modern Laravel, so this package inherits that floor.composer why laravel/nova to see what is currently resolved, and confirm your composer.json pins Nova explicitly ("laravel/nova": "^4.0") rather than relying on implicit resolution.Install (typical flow)
composer require vendor/package:^2.0
php artisan vendor:publish --provider="Vendor\Package\PackageServiceProvider" # config/migrations/assets
php artisan migrate
php artisan nova:publish # Nova's own public assets
npm install && npm run build # if the package ships compiled assets via your app
Where to look first
README.md — the Nova 4 upgrade section is the only thing that changed; read it before the feature docs.CHANGELOG.md / PR #26 diff — confirms whether Nova 3 support was dropped or merely superseded.config/<package>.php — the knobs you will actually touch day to day.src/ provider — how the package registers itself (Nova::tools(), Nova::cards(), Nova::scripts(), or resource/field bootstrapping).resources/js/ — only if you need to customise the Vue component; Nova 4 is Vue 3, so any local fork of the package's front end must be Vue 3-compatible.First use case
Register the component in app/Providers/NovaServiceProvider.php and load a dashboard:
public function tools()
{
return [
new \Vendor\Package\Tool(),
];
}
protected function dashboards()
{
return [
(new Main)->cards([
new \Vendor\Package\Card(),
]),
];
}
For a field-style package, drop it on a resource and hit the index and detail screens — those exercise the two most common failure points (serialization on index, resolveUsing on detail).
Gate everything through Nova's authorization API
The cheapest day-to-day win is putting package components behind canSee / canRun rather than duplicating permission logic in policies:
(new \Vendor\Package\Tool())->canSee(fn ($request) => $request->user()->can('viewOps'));
Do the same for Card, Filter, and Metric. Remember canSee is evaluated per request on dashboard render — avoid DB hits inside it; cache the permission check on the user model.
Field packages: separate the three display contexts
Nova fields behave differently on index, detail, and form. Write them so each context is explicit:
Field::make('Status')
->rules('required', 'in:open,closed')
->sortable() // index
->onlyOnForms() // or ->hideFromIndex() / ->hideWhenUpdating()
->resolveUsing(fn ($value) => strtoupper($value));
fillUsing handles inbound writes; resolveUsing handles outbound reads. A field that "works on detail but shows blank on index" is almost always missing a resolveUsing or a displayUsing callback.
Config-first, code-second
Publish the config and drive behaviour from it. Then read config keys from config/<package>.php (with env() only inside that file — never call env() from package source, it breaks under config:cache).
Register custom JS/CSS once, globally
If the package ships a script or style hook:
// NovaServiceProvider::boot()
Nova::script('vendor-package', __DIR__.'/../vendor/vendor/package/dist/js/tool.js');
Combine this with Nova::provideToScript([...]) for runtime values rather than hardcoding URLs in the Vue component.
Testing and CI
Nova is a private Composer repository, so CI needs credentials before composer install:
composer config http-basic.nova.laravel.com "$NOVA_USERNAME" "$NOVA_PASSWORD"
Then:
Nova::actingAs($user) and assert 403/200 on the tool's route.Laravel\Nova\Testing\Browser\Pages\Dashboard) for anything that genuinely depends on the Vue layer — this is the only reliable way to catch a Nova 4 front-end regression.Upgrade workflow for 1.x → 2.0.0
^2.0.--force, then diff the published files against your repo copies. Published configs are the #1 source of "the new option doesn't work".php artisan optimize:clear, then rebuild caches for prod.php artisan nova:tool, nova:card, nova:field) and port your logic — do not try to hand-patch a Vue 2 component.If you must support Nova 3 and 4 simultaneously
Keep a 1.x maintenance branch rather than branching inside the package. Nova's front-end break is not something you can cleanly shim; a version constraint on laravel/nova per release line is the sane split.
The major version bump is the headline, not the feature
PR #26 is one line in the changelog for a large amount of work: Nova 4 changed its front-end stack (Vue 3) and raised the framework/PHP floor. Treat 2.0.0 as "this package is now a Nova 4 package", and audit your own customisations accordingly. Nothing in the note suggests a deprecation path for Nova 3 — assume it was dropped.
Compiled assets are the classic upgrade failure
A tool that renders a blank panel after upgrading is usually serving a stale published asset bundle. Re-run php artisan nova:publish and, if the package ships its own tag, vendor:publish --tag=<package>-assets --force. Bump any cache-busting version key you control.
config:cache hides new config keys
If you deploy with php artisan config:cache, a newly published config file is not picked up until you re-cache. Symptom is a package silently falling back to defaults. Add php artisan optimize:clear to the deploy script after publishing.
Silent 403s from canSee / authorizedToRun
Nova hides components you are not authorised to see — no error, no log line. When "the tool disappeared after upgrade", check the policy/canSee callback first, and verify with a user that bypasses policies (e.g. Nova::actingAs a super-admin in a test).
Index vs detail vs form
As above, but worth repeating because it is the most common field bug: values resolved for display are not the same pipeline as values filled from a form. Test all three contexts after upgrading, since Nova 4 changed some serialization details.
Nova is not on Packagist
Version resolution for laravel/nova can silently satisfy an older constraint if your local composer.json is loose. Pin it, lock it, and make sure the CI credentials secret exists — an auth failure on nova.laravel.com surfaces as a confusing "package not found" rather than a 401.
Performance: cache cards and metrics
Nova 4 dashboards render cards on every load. Use ->cacheFor(now()->addMinutes(5)) on metrics and avoid unbounded queries in calculate(). Filters run a query per filter definition per request — index the columns you filter on.
Debugging checklist
php artisan route:list | grep nova — confirms the component's routes exist at all.storage/logs/laravel.log — Nova swallows most component exceptions into a generic error toast; the stack trace is here./nova-api/... call means the PHP side is fine but the response shape changed (common when mixing Nova 3-era JSON expectations with Nova 4).composer show laravel/nova — confirm you are actually on 4.x before debugging anything else.Extension points worth knowing
vendor/.Nova::script() / Nova::style() / Nova::provideToScript() for injecting global front-end behaviour from a service provider.protected methods or a Contracts/ directory), prefer container binding over subclassing — $this->app->bind(...) in your NovaServiceProvider survives package minor bumps better.Pin and read the changelog on every future bump
Given that the only documented change here is a framework-version jump, this package is one where a patch release can still mean "different Nova generation". Snapshot the current working state (composer.lock, published config, published assets) before any further update so a rollback is a checkout, not an archaeology project.
How can I help you explore Laravel packages today?