Laravel Query Builder

Turn API request query strings into safe, allow-listed Eloquent filters, sorts, and includes

Library
Composer
v7.3.3
4,465stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
78/100Good
Development Activity68
Maintenance72
Community72
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
85/100Excellent
Architecture85
Code Quality88
Innovation84
Learning Curve82

Laravel Query Builder is a Spatie package that translates the query-string conventions of a JSON:API-style request (filter[name]=John, sort=-created_at, include=posts, fields[users]=id,email) directly into an Eloquent query. Instead of hand-rolling conditional if statements for every filterable or sortable column in a controller, developers declare an allow-list of filters, sorts, includes, and fields on a QueryBuilder::for() call, and the package parses the incoming request and applies matching clauses automatically.

It is built specifically for API endpoints where clients need flexible, self-service querying without exposing the full Eloquent query surface to untrusted input. Every filter, sort, and include must be explicitly allowed, so unexpected or malicious query parameters are rejected with a typed exception rather than silently reaching the database layer.

What You Get

  • A QueryBuilder::for(Model::class) entry point that behaves like a normal Eloquent builder via __call forwarding, so any existing builder method still works
  • AllowedFilter types for exact, partial, scope-based, callback-based, begins-with/ends-with, operator, and grouped OR/AND filters
  • AllowedInclude support for eager-loading relationships, relationship counts, sums, averages, min/max, and existence checks straight from ?include=
  • AllowedSort support for field-based and custom callback-based sorting via ?sort=, including descending order with a - prefix
  • Sparse fieldset support via ?fields[table]=col1,col2 to limit which columns are selected per included model
  • Typed exceptions (InvalidFilterQuery, InvalidSortQuery, InvalidIncludeQuery, InvalidFieldQuery, etc.) thrown when a request references something not on the allow-list

Common Use Cases

  • Building a public or partner-facing REST API where consumers need to filter, sort, and include related resources without the backend team adding a new endpoint for every combination
  • Replacing repetitive if ($request->has('filter')) conditionals scattered across resource controllers with a single declarative allow-list
  • Enforcing that only vetted columns and relationships can be queried by API clients, closing off accidental data exposure or N+1-inducing arbitrary includes
  • Adding JSON:API-style query conventions to an existing Laravel API without adopting a full JSON:API package

Under The Hood

Architecture - The package centers on QueryBuilder (src/QueryBuilder.php), which wraps an injected Eloquent Builder or Relation and composes four traits — FiltersQuery, AddsIncludesToQuery, SortsQuery, and AddsFieldsToQuery — each responsible for one query concern. QueryBuilder::for() is the entry point: it resolves the current request into a QueryBuilderRequest (a Illuminate\Http\Request subclass that parses filter[], sort, include, and fields[] query parameters, including delimiter-aware array parsing), then each trait’s allowedX() method cross-references the parsed request against a developer-declared allow-list before mutating the underlying builder. Unmatched calls fall through to the wrapped Eloquent builder via ForwardsCalls::forwardCallTo() in __call, and ArrayAccess/__get/__set are implemented so the object is interchangeable with a real builder in most contexts.

Tech Stack - Requires PHP ^8.3 and Laravel (illuminate/database, illuminate/http, illuminate/support) ^12.0|^13.0, registered via spatie/laravel-package-tools. Dev tooling uses Pest ^4.0 and PHPUnit ^12.0 for tests, Larastan (PHPStan for Laravel) ^3.0 with a checked-in baseline for static analysis, Orchestra Testbench ^10.0|^11.0 to run tests against a real Laravel app skeleton, and Mockery for mocking — a conventional, current Spatie/Laravel package stack with no exotic dependencies.

Code Quality - The tests/ directory contains 24 PHP test files covering filters, includes, sorts, field selection, request parsing, and the public QueryBuilder API, run via composer test (Pest). A phpstan-baseline.neon and phpstan.neon.dist show static analysis is enforced in CI with a tracked baseline rather than being aspirational. Source classes are narrowly scoped (one filter type per class under src/Filters/, one include type per class under src/Includes/), use PHP 8 constructor property promotion, and are annotated with generic PHPDoc templates (@template TModel of Model) for IDE support despite PHP’s lack of native generics — a sign of deliberate API ergonomics investment rather than just functional correctness.

API Design - The public surface is a single static entry point, QueryBuilder::for($subject, $request), that mimics Eloquent’s own fluent builder style (->allowedFilters()->allowedIncludes()->allowedSorts()->get()), so Laravel developers can adopt it with near-zero new mental model. Because unknown method calls forward to the wrapped builder, existing Eloquent knowledge (where(), withTrashed(), custom scopes) keeps working unchanged inside the chain. Extensive docs (docs/features/, docs/advanced-usage/) cover filtering, sorting, includes, and field selection with runnable examples, and typed exceptions per failure mode make it straightforward to map invalid requests to specific HTTP error responses.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search