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 Custom Controller Laravel Package

opanegro/nova-custom-controller

A Laravel Nova package that lets you attach custom controllers to Nova resources, offering flexibility beyond Nova's default CRUD handling. Useful for custom actions, workflows, and tailored admin behavior while keeping Nova's familiar UI.

View on GitHub
Deep Wiki
Context7

Getting Started

opanegro/nova-custom-controller exists to solve one narrow problem: Nova encourages you to build pages and tools as Vue SPAs, but sometimes you just need a plain Laravel controller behind Nova's auth — a CSV export, a webhook receiver, a bulk action endpoint, a file download. This package gives you a supported way to register those controllers inside Nova's route/middleware stack instead of hand-rolling it.

Minimal steps:

  1. composer require opanegro/nova-custom-controller
  2. Confirm the service provider was auto-discovered (bootstrap/providers.php on Laravel 11+, or config/app.php on older versions). If not, add Opanegro\NovaCustomController\...ServiceProvider manually.
  3. Open the README's single example block first — that is the whole API surface. Then read vendor/opanegro/nova-custom-controller/src/ to see exactly which routes and middleware the provider registers. The package is thin enough to audit in five minutes, which matters given its age.
  4. Create a normal controller extending App\Http\Controllers\Controller, add the AuthorizesRequests trait, and point the package's registration config at it.
  5. Trigger it from the Nova front end with Nova.request() (or a plain <a href> for downloads).

First use case: an "Export CSV" button on a resource index. You add a controller action that streams User::all() as CSV, register it through the package, and call it from a custom button or a Nova action's handle() via redirect. That is the 80% case for this package.

Implementation Patterns

Route-per-action, not resource controllers. Nova endpoints are usually verbs against a resource collection, not CRUD. Keep controllers small and single-purpose (ExportUsersController, ImportOrdersController) and register one route each. It reads better in route:list under the nova-vendor/ prefix.

Return JSON for SPA consumption. Anything a Vue component calls should return response()->json(...) and be fetched with Nova.request().get('/nova-vendor/opanegro/...'). Nova.request() already carries the XSRF token and Nova's axios config, so POSTs work without extra setup — provided the route sits in the web middleware group.

Downloads and streams. For exports use response()->streamDownload(fn () => ..., 'users.csv') and hit the URL with a normal anchor tag; don't route it through Nova.request(), which tries to parse the body.

Authorization inside the controller. The package puts you behind Nova's auth middleware, but that only proves someone is logged in. Add explicit policy checks:

public function __invoke(Request $request)
{
    $this->authorize('viewAny', User::class);
    // ...
}

Extract business logic into a service. If the same export is triggered from a Nova Action and from a custom button, both should call UserExporter — the controller becomes a thin HTTP adapter. This also makes the logic testable without Nova booted.

Testing. Use $this->actingAs($admin, config('nova.guard')) in feature tests; testing against the default guard will 302-redirect and confuse you.

Gotchas and Tips

  • This package predates Nova 4. Last release was December 2019, which puts it firmly in the Nova 2/3 era. Nova 4 moved the SPA to Inertia and changed route prefixes (/nova-api), middleware groups, and the request/response contract. Verify against your Nova version before installing; on Nova 4+ you will likely need to fork it or just register the routes yourself. The entire package is essentially:

    Route::middleware(['nova'])
        ->prefix('nova-vendor/opanegro/custom')
        ->group(function () {
            Route::get('/export', ExportController::class);
        });
    

    If the package fights you, copy that pattern into your own provider. You lose nothing.

  • Auth guard mismatches. If your users authenticate on a non-default guard, Nova routes will 401/redirect. Check config('nova.guard') and ensure the nova middleware group is picking it up. This is the number-one cause of "route exists but I get bounced to login."

  • CSRF on POSTs. Routes registered outside the web group skip VerifyCsrfToken, so Nova.request() POSTs will fail with 419. Confirm the package includes web in the middleware stack — if not, add it in your own route registration.

  • Route caching. If the package's config accepts closures or dynamic route definitions, php artisan route:cache will fail in production. Use controller class strings only.

  • Don't expose these routes without the Nova middleware. A controller registered as a plain web route is a public endpoint with only your authorize() call standing between an attacker and your data. Audit route:list --path=nova after every change.

  • Debugging: php artisan route:list --path=nova-vendor is faster than reading source. Then Log::info() at the top of the controller to confirm the request even arrives — middleware rejection produces silent redirects that look like routing bugs.

  • Maintenance risk. 14 stars, single author, four-plus years stale. Treat it as a reference implementation rather than a dependency you can rely on across Nova upgrades. Pinning it is fine; building a long-term feature on its API is not.

  • Extension points are minimal. There's no event system or plugin surface here — the provider registers routes and gets out of the way. Any customization happens in your controller and your route registrations, which is the right place for it anyway.

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.
htinlynn/genius-helper
maco-studios/hephaestus
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