liqrgv/query-filter-laravel
A Laravel package for building expressive, reusable query filters. Apply request-based filtering, sorting, and search to Eloquent queries with clean, composable filter classes—ideal for APIs and admin lists.
Architecture fit
liqrgv/query-filter-laravel targets the request-to-Eloquent boundary — the layer where HTTP query strings (?filter[status]=active&sort=-created_at) are translated into a Builder chain. Architecturally this is a thin, high-leverage seam: it sits in the controller/FormRequest layer and composes with Laravel’s existing pipeline (middleware → FormRequest validation → controller → resource serialization) rather than replacing any of it. The main fit question is whether the package is a trait-based approach on a Request object or a standalone filter/resolver class. Trait-on-Request is ergonomic inside controllers but couples filtering to the HTTP layer, which hurts reuse in console jobs, GraphQL resolvers, or internal service calls. A standalone resolver is the more portable design and the one to prefer if we plan to reuse filter definitions across entry points.
Integration feasibility
Low surface-area install: composer require, optional config publish, and one or two lines per controller. Realistic effort is hours-to-days for a single endpoint, not weeks. The gating factor is not installation but convention: we need a team-wide answer to "what does a filter definition look like, where does it live, and how is it named?" Without that, the package becomes a fifth filtering idiom alongside manual when() clauses, scopes, and any existing query-builder library.
Technical risk
0.41 score and absence of evidence on release cadence should be treated as the headline risk.whereRaw/orderByRaw path is reachable from user input. Missing allow-listing here is a SQL-injection or data-exposure class of bug.?sort=body_text on a large table). Needs coupling to an allowed-sort list and ideally a max on relation depth.spatie/laravel-query-builder (i.e., is this a substitute or a complement?).Key questions
Request object, or bound to it?spatie/laravel-query-builder (broad adoption, explicit allow-listing, documented JSON:API semantics)?Stack fit Good fit for a conventional Laravel JSON API backed by Eloquent. It is a convention layer, not infrastructure — it does not touch the container, caching, queues, or auth. That keeps blast radius small and makes it easy to trial and easy to remove. It is a poor fit if we have non-Eloquent data sources, GraphQL, or a strong preference for repository/query-object patterns that already own this concern.
Migration path Three realistic starting points, in increasing cost:
when() filtering — introduce package filters behind the existing controller signature so the HTTP contract is unchanged; filtering becomes declarative per endpoint. Low risk, incremental.spatie/laravel-query-builder or custom scopes — only worth it if this package's ergonomics are demonstrably better. Absent a compelling delta, a migration is unjustified churn on a 10-star dependency.Compatibility
Verify before committing: Laravel 10/11/12 support, PHP 8.2+, illuminate/* constraint breadth, and coexistence with pagination and API Resource layers. Pin the minor version in composer.json and rely on Renovate/Dependabot with a mandatory review gate — pre-1.0 packages should never auto-merge.
Sequencing
?filter[user.password]=x.index endpoint. Wrap filter definitions in our own BaseFilter abstraction so the package API is isolated behind one internal seam.filter[...], sort, include) into an OpenAPI spec and feature tests so the API contract survives a future package swap.Maintenance The dominant cost is dependency stewardship, not code. Assume we will eventually own this code: either vendoring it (fork under our namespace, Apache-2.0 permits this) or replacing it. Budget for quarterly review of upstream activity; if the repo goes 6+ months without commits, the pre-agreed action is to vendor the ~few-hundred lines rather than wait. The abstraction seam in the pilot step is what makes that a half-day task instead of a refactor.
Support No vendor, no SLA, no CVE feed. Internal support = the backend guild. Document the grammar and the allow-list rule in the team wiki; the convention will generate more questions than the code.
Scaling
Query-filtering scales fine at the application tier — it is stateless per-request work. The scaling risk is entirely on the database: unbounded sort/filter on non-indexed columns. Mitigate with a hard allow-list per endpoint, an index review for every permitted sort column, and (if offered) a cap on relation depth. Load-test one high-traffic index endpoint with worst-case filter combinations rather than assuming.
Failure modes
with()/eager loading; the package will not do this for you.Ramp-up
Low for the consumer side — a backend engineer productive in under a day; the grammar is small. Higher for the owner side: one engineer should read the source end-to-end and become the named owner before rollout, precisely because upstream documentation and community answers will not exist. Treat this as a "one owner, one pilot, documented escape hatch" adoption — not a team-wide standard until it has survived a security review and a quarter in production. Given the 10-star, 0.41-score profile, the honest recommendation is conditional: adopt behind an internal abstraction, or default to spatie/laravel-query-builder if the team has no specific reason to prefer this one.
How can I help you explore Laravel packages today?