Laravel Pipeline: Clean & Powerful Query Filtering
In modern Laravel applications, data filtering often becomes messy as requirements grow. From searching by a keyword, to sorting, to filtering by authors — controllers can quickly become cluttered with if and when() helper conditions.
Laravel’s Pipeline provides a powerful, elegant way to manage this complexity. By sending your query through a series of independent filters, you achieve a clean, testable, and highly maintainable solution.
Why Laravel Pipeline?
Let’s say you have this classic scenario:
if ($request->has('title')) { $query->where('title', 'like', ...);}if ($request->has('sort')) { $query->orderBy(...);}// and more...
As new filters are added, these blocks become harder to manage. The Pipeline pattern instead allows you to split each filter into its own class, run them in sequence, and keep your controller clean.
Pipeline in Action
Here’s an example from a real-world controller:
<?php declare(strict_types=1); namespace App\Http\Controllers\Api\V1; use App\Filters\SortFilter;use App\Filters\TypeFilter;
use App\Filters\CategoryFilter;use App\Models\Post as Article;use Illuminate\Http\JsonResponse;use App\Filters\SearchByTitleFilter;use App\Http\Controllers\Controller;use App\Filters\UsernameAuthorFilter;use App\Http\Resources\ArticleResource;use Illuminate\Support\Facades\Pipeline;use App\Http\Requests\Api\V1\ArticleFilterRequest;use Symfony\Component\HttpFoundation\Response as HttpResponse; final class ArticleController extends Controller{ public function index(ArticleFilterRequest $request): JsonResponse { $request->validated(); $query = Article::query() ->with(['author', 'categories', 'likes']) ->select('posts.*'); $pipes = [ SearchByTitleFilter::class, SortFilter::class, UsernameAuthorFilter::class, TypeFilter::class, CategoryFilter::class, ]; $articles = Pipeline::send($query) ->through($pipes) ->thenReturn() ->visible() ->paginate($request->get('per_page')); return response() ->json([ 'status' => HttpResponse::HTTP_OK, 'message' => 'Articles retrieved successfully.', 'data' => ArticleResource::collection($articles), 'meta' => [
'current_page' => $articles->currentPage(), 'last_page' => $articles->lastPage(), 'per_page' => $articles->perPage(), 'total' => $articles->total(), 'from' => $articles->firstItem(), 'to' => $articles->lastItem(), 'next_page_url' => $articles->nextPageUrl(), 'prev_page_url' => $articles->previousPageUrl(), ], ], HttpResponse::HTTP_OK); }}
The given code was from Laranepal while working on apis for articles.
What’s happening here?
- ✅ You define a base query
- ✅ You list your filtering classes (pipes)
- ✅ The pipeline sends the query through each pipe
- ✅ You receive the final filtered query for pagination
This pattern removes dozens of if statements and replaces them with reusable, testable filters.
Example Filter Class
For example, your SearchByTitleFilter might look like this:
<?php declare(strict_types=1); namespace App\Filters; use Closure;use Illuminate\Http\Request;use Illuminate\Database\Eloquent\Builder; final readonly class SearchByTitleFilter{ public function __construct(private Request $request) {} public function handle(Builder $builder, Closure $next) { return $next($builder) ->when( $this->request->has('search'), fn ($query) => $query->where('title', 'REGEXP', $this->request->search) ); }}
Each filter is small, focused, and reusable. Adding a new filter only means creating another class and adding it to the pipeline.
Benefits of Laravel Pipeline
- ✅ Cleaner controllers — avoid bloated logic
- ✅ Single Responsibility — each filter class handles one task
- ✅ Testable — filters can be unit-tested in isolation
- ✅ Extensible — new filters can be added or removed easily
- ✅ Consistent — data always flows through predictable steps
Learn More
Laravel documents the pipeline helper here: 👉 Laravel Pipeline Documentation
Pipelines aren’t limited to queries — you can use them for data transformations, business logic, or even request handling. They’re an underused yet powerful feature in any Laravel toolbox.
Conclusion
Laravel’s Pipeline pattern is a clean, scalable solution to query filtering. It keeps your controllers lean, promotes separation of concerns, and makes your codebase easier to test and maintain. If you’re building APIs with complex filtering, start leveraging pipelines today — your future self (and your teammates) will thank you!
Senior Software Engineer • Writer @ Laranepal • PHP, Laravel, Livewire, TailwindCSS & VueJS • CEO @ Laranepal & Founder @ laracodesnap
Shivaji Chalise