1 min read

Custom Eloquent Builders in Laravel: Write Cleaner, Reusable Queries

Custom Eloquent Builders are one of the most underrated features in Laravel. They allow you to move complex query logic out of your models and controllers into dedicated builder classes, making your code cleaner, reusable, and easier to maintain.

If you've ever written the same where(), orderBy(), or filtering logic in multiple places, a custom builder is worth considering.


The Problem

Imagine you have a Post model. Throughout your application, you frequently need to fetch published posts.

Without a custom builder, you might write something like this repeatedly:

Post::query()
    ->where('status', 'published')
    ->where('published_at', '<=', now())
    ->latest()
    ->get();

Soon, this query appears in controllers, jobs, commands, and API endpoints. If the business rule changes, you'll have to update it everywhere.


The Better Approach

Create a dedicated builder.

<?php

namespace App\Models\Builders;

use Illuminate\Database\Eloquent\Builder;

class PostBuilder extends Builder
{
    public function published(): static
    {
        return $this
            ->where('status', 'published')
            ->where('published_at', '<=', now());
    }

    public function featured(): static
    {
        return $this->where('is_featured', true);
    }
}

Now tell your model to use it.

<?php

namespace App\Models;

use App\Models\Builders\PostBuilder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class Post extends Model
{
    public function newEloquentBuilder($query): Builder
    {
        return new PostBuilder($query);
    }
}

Now your queries become much more expressive.

Post::query()
    ->published()
    ->featured()
    ->latest()
    ->get();

Why Use Custom Builders?

1. Reusable Query Logic

Instead of duplicating the same conditions across your application, define them once and reuse them everywhere.


2. Cleaner Models

Many developers add dozens of local scopes to a model.

scopePublished()
scopeFeatured()
scopePopular()
scopeArchived()
scopeTrending()
scopeVisible()

As your application grows, models become cluttered.

Moving query logic into a dedicated builder keeps the model focused on representing the entity rather than every possible query.


3. Better Readability

Compare these two queries.

Post::query()
    ->where('status', 'published')
    ->where('published_at', '<=', now())
    ->where('is_featured', true)
    ->latest();

vs

Post::query()
    ->published()
    ->featured()
    ->latest();

The second version reads almost like English.


4. Easier Maintenance

Suppose the definition of a published post changes.

Instead of updating dozens of queries, you only modify one method.

public function published(): static
{
    return $this
        ->where('status', 'published')
        ->whereNotNull('published_at')
        ->where('published_at', '<=', now());
}

Every query using published() immediately benefits from the update.


5. Great for Large Applications

As your SaaS grows, you'll often have reusable filters like:

  • Active users
  • Paid subscriptions
  • Verified customers
  • Pending invoices
  • Recent orders
  • Completed payments

Custom builders keep these queries organized and easy to discover.


When Should You Use Them?

Custom builders are a great choice when:

  • Multiple queries share the same filtering logic.
  • Your model has too many local scopes.
  • You want more expressive, chainable query methods.
  • You're building medium-scale to large-scale Laravel applications or SaaS products.

For very small applications, local scopes are often sufficient. But as your codebase grows, custom builders provide a cleaner structure.


Final Thoughts

Custom Eloquent Builders are a simple yet powerful way to organize query logic in Laravel. They help reduce duplication, improve readability, and make your application easier to maintain as it grows.

If your models are filled with dozens of local scopes or you find yourself copying the same query conditions repeatedly, moving that logic into a custom builder can make a significant difference.

It's one of those Laravel features that many developers overlook, but once you start using it, you'll likely wonder how you managed without it.

Featured Projects

Beyond enterprise work, I build open-source tools and "spare-time" projects to push the boundaries of the Laravel ecosystem. Explore a collection of my technical experiments and side-hustles.

Open Source
Laravel Packages
SaaS Boilerplates