akki-io/laravel-nova-search
A Laravel Nova package that enhances global search, making it easier to find records across your resources. It adds flexible search capabilities to the Nova admin panel, helping admins navigate large datasets quickly and efficiently.
Verify your Nova major version first. v2.0.0 exists specifically to support Nova 5, so check composer show laravel/nova before installing. If you are still on Nova 4, stay on the 1.x line — the 2.x branch is a major bump and should be treated as Nova-5-only.
composer require akki-io/laravel-nova-search:^2.0
php artisan vendor:publish --tag=nova-search-config # if a config is exposed
php artisan optimize:clear
Nova is a commercial package, so make sure your composer.json has the nova.laravel.com repository and credentials configured — a fresh install failing on laravel/nova resolution is almost always an auth problem, not a package problem.
Where to look first: the package's src/ for the applySearch implementation and any ServiceProvider macro registration, then your own resources that override or call it. The single change in this release is the addition of typings to applySearch, so the first thing to read is that method's new signature and compare it to anything in your codebase that implements or overrides the same name.
First use case: take one Nova resource with a slow or imprecise search experience, wire applySearch into its index query, and confirm column matches behave as expected before rolling it out to the rest.
// app/Nova/User.php
public static function indexQuery(NovaRequest $request, $query)
{
return $query->applySearch($request->search);
}
Resource-level integration. The common shape is calling applySearch from indexQuery() so every Nova index request gets consistent search semantics. Keep other index-time concerns (authorization scopes, eager loads) separate so this stays a pure query-builder concern.
Model trait composition. If you search across many models, wrap the call in a small trait or base resource rather than repeating the request plumbing:
public static function indexQuery(NovaRequest $request, $query)
{
return $query
->when($request->search, fn ($q) => $q->applySearch($request->search))
->when($request->filter('trashed') === 'with', fn ($q) => $q->withTrashed());
}
Wrapping in when() keeps the macro from firing on unfiltered index loads, which is both faster and less surprising.
Qualify columns when joining. As soon as your index query joins tables (lenses, relationship filters), unqualified column names in the search list cause ambiguous-column errors. Define search columns fully qualified (users.name, teams.label) and mirror whatever the package's config or argument expects.
Test around the macro, not the framework. Write feature tests that hit the Nova index endpoint with ?search=... and assert on returned IDs. This catches both the SQL behaviour and the typing compatibility in one shot, and it survives Nova upgrades better than unit-testing the macro directly.
If you maintain Nova 4 and 5 support simultaneously, run a composer matrix with the Nova version constrained as a branch alias. The 2.x typings will fatally fail to satisfy Nova 4's looser contract in subclasses, so the two versions generally need to be shipped as separate constraint entries rather than one universal tag.
The major bump is the typings, and typings are contagious. Adding parameter and return types to applySearch means any subclass, trait using the same method name, or anonymous class in your app that overrides it must now match the signature. PHP will throw a fatal Declaration must be compatible error at class-load time, not at call time — so it surfaces as a 500 on the first request that autoloads the class. Run composer dump-autoload and exercise the affected resources immediately after upgrading.
Nova 5 tightened its own contracts too. If you upgrade Nova and this package in the same deploy, a fatal signature error could originate from your resource's fields(), cards(), filter(), or from applySearch. Bisect by upgrading one at a time; otherwise you will attribute the package's change to the wrong culprit.
LIKE wildcards are unescaped user input. Anything that expands a search term into %term% needs %, _, and the escape character neutralised, or a search for 100% returns everything. If the package does not escape for you, escape at the call site.
Search performance degrades quietly. LIKE '%term%' cannot use a B-tree index. On tables past a few hundred thousand rows the Nova index becomes noticeably slow and the usual symptom is a timeout that looks like a Nova problem. Add a full-text index or a dedicated search column and route through a whereFullText clause, keeping applySearch for the small tables.
Double-filtering is easy to miss. Nova already filters on columns marked ->searchable(). If you call applySearch on the same columns, you get redundant WHERE clauses that inflate the query and can produce duplicate JOIN rows. Pick one mechanism per resource and stay consistent.
Pin the minor line in production. With one PR in the release and no changelog detail beyond the typings, treat 2.0.x as young. composer.lock plus a ^2.0 constraint is right; floating to dev-main on a Nova dependency is not.
Debugging tip: when search returns nothing unexpectedly, dump the query before and after the macro with ->toSql() and ->getBindings(). Nova's request object is not always eagerly populated with search, and an empty string passed into the macro can silently short-circuit to a no-op clause instead of returning all rows.
How can I help you explore Laravel packages today?