Copied!
Laravel

How to Implement the Repository Pattern in Laravel — Clean and Scalable Architecture

implement-the-repository-pattern-in-laravel
Shahroz Javed
Oct 22, 2025 . 20 views

Table Of Contents

 

Introduction

When building large Laravel applications, your controllers and models can easily become bloated — full of query logic, validation, and data handling. This makes your code harder to maintain and test.

The Repository Pattern helps you solve this by separating your data access logic from your business logic. It acts as an abstraction layer between your controllers (or services) and your models, allowing you to write cleaner, testable, and scalable code.

💡 Related: You may also like our guide on Using DTOs in Laravel for Cleaner Data Handling.

Why Use the Repository Pattern?

The Repository Pattern helps structure your Laravel codebase more cleanly. Instead of directly calling Eloquent methods inside controllers, you delegate all database interactions to repository classes.

When to Use It

Use the Repository Pattern when your app starts growing — especially if:

⚠️ Note: The Repository Pattern is not necessary for very small apps. It shines when your codebase or team grows.

Implementing the Repository Pattern in Laravel

Let’s walk through a step-by-step example using a Vehicle model.

Step 1: Create a Repository Interface

We’ll define an interface that declares methods for interacting with the data layer.

<?php

namespace App\Repositories;

interface VehicleRepositoryInterface
{
    public function all();
    public function find(int $id);
    public function create(array $data);
    public function update(int $id, array $data);
    public function delete(int $id);
}

Step 2: Implement the Repository

Next, create a class that implements this interface and interacts with the Eloquent model.

<?php

namespace App\Repositories;

use App\Models\Vehicle;

class VehicleRepository implements VehicleRepositoryInterface
{
    public function all()
    {
        return Vehicle::latest()->get();
    }

    public function find(int $id)
    {
        return Vehicle::findOrFail($id);
    }

    public function create(array $data)
    {
        return Vehicle::create($data);
    }

    public function update(int $id, array $data)
    {
        $vehicle = Vehicle::findOrFail($id);
        $vehicle->update($data);
        return $vehicle;
    }

    public function delete(int $id)
    {
        return Vehicle::destroy($id);
    }
}

This class now acts as a single source of truth for all Vehicle data operations.

Step 3: Bind Interface to Implementation

Tell Laravel which implementation to use when the interface is requested. Add this binding in AppServiceProvider:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Repositories\VehicleRepositoryInterface;
use App\Repositories\VehicleRepository;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(VehicleRepositoryInterface::class, VehicleRepository::class);
    }
}

Step 4: Use Repository in Controller

Now inject the repository into your controller instead of using the model directly.

<?php

namespace App\Http\Controllers;

use App\Repositories\VehicleRepositoryInterface;
use Illuminate\Http\Request;

class VehicleController extends Controller
{
    protected VehicleRepositoryInterface $vehicles;

    public function __construct(VehicleRepositoryInterface $vehicles)
    {
        $this->vehicles = $vehicles;
    }

    public function index()
    {
        return response()->json($this->vehicles->all());
    }

    public function store(Request $request)
    {
        $vehicle = $this->vehicles->create($request->all());
        return response()->json($vehicle, 201);
    }

    public function show($id)
    {
        return response()->json($this->vehicles->find($id));
    }

    public function update(Request $request, $id)
    {
        return response()->json($this->vehicles->update($id, $request->all()));
    }

    public function destroy($id)
    {
        $this->vehicles->delete($id);
        return response()->json(['message' => 'Vehicle deleted']);
    }
}

Result

Your controller is now clean, focused, and independent from your database structure. You can easily switch to a different data source or mock your repository during testing.

Laravel Repository Pattern Clean Architecture
Clean and modular code structure using Repository Pattern

Advantages of Repository Pattern in Laravel

⚠️ Pro Tip: Combine the Repository Pattern with DTOs and Service Layers for a truly enterprise-grade Laravel architecture.

Conclusion

The Repository Pattern is one of the most effective ways to keep your Laravel application’s architecture clean and scalable. It removes repetitive query logic from controllers, promotes consistency, and prepares your codebase for long-term growth.

If you’re working on a growing Laravel project, start implementing repositories early — your future self (and your team) will thank you.

19 Shares

Similar Posts