LaravelArchitectureRepository PatternDDD

Understanding Design Patterns in Laravel: From MVC and Repository to DDD

Sodiq Ardianto•04 Mar 2026•4 min read

Understanding Design Patterns in Laravel: From MVC and Repository to DDD

1. The Default Approach: MVC (Model-View-Controller)

  • Model: Responsible for interacting with the database (using an ORM like Eloquent).
  • View: Handles the presentation to the user (via Blade Templates or JSON Responses).
  • Controller: The bridge that receives HTTP requests from Routes, processes data through Models, and returns it to Views/APIs.

When to Use Standard MVC?

2. Database Abstraction: Repository Pattern

PHP
// In UserController$activeUsers = User::where('status', 'active')->whereNotNull('email_verified_at')->get();// In InvoiceController$activeUsers = User::where('status', 'active')->whereNotNull('email_verified_at')->get();

Implementation:

PHP
class UserRepository {    public function getActiveVerifiedUsers() {        return User::where('status', 'active')->whereNotNull('email_verified_at')->get();    }}
PHP
public function index(UserRepository $userRepo) {    $users = $userRepo->getActiveVerifiedUsers();    return view('users.index', compact('users'));}

When to Use It?

  • You frequently rewrite the same Eloquent queries repetitively, and they are scattered across your codebase.
  • You have a strong need for easier Unit Testing (easily mocking data operations without touching the actual database).

3. Enterprise Scale: Domain-Driven Design (DDD)

Modular Concept (Bounded Context):

Code
src/└── Domain/    ├── Invoicing/    │   ├── Controllers/    │   ├── Models/    │   ├── Repositories/    │   └── Actions/    │    └── HumanResource/        ├── Controllers/        ├── Models/        └── Repositories/

When to Use It?

Conclusion: The Right Tool for the Right Job

  • MVC: Fast (Rapid development), Laravel's default, for small to medium projects.
  • Repository: When things start getting complex, to solve repetition at the database layer, and to support layered testing.
  • DDD: For massive scale (enterprise), where the territorial boundaries of system logic are paramount, dividing repositories per domain (high complexity).

As a Laravel developer, we often face the question: *"How should I structure my code to keep it clean and maintainable as the application grows?"* Laravel natively uses the **MVC (Model-View-Controller)** architecture, which is highly intuitive. However, as the complexity of features and business logic increases, Controller code often becomes bloated and difficult to maintain. This is where advanced architectural patterns like the **Repository Pattern** and **Domain-Driven Design (DDD)** come into play. Let's dissect these three approaches, understand their place, and know exactly when to use them. The MVC pattern is how the Laravel framework separates application logic by default. Standard MVC is perfectly fine and fast for **small to medium-scale applications**. If your logic is as simple as validating a request and calling `Product::create($request->validated())`, stick with pure MVC. Implementing overly complex patterns (over-engineering) at this stage will only slow down your development and project completion time. As an application grows moderately, you'll start encountering querying scenarios that are repeated across multiple Controllers. A bad example: The **Repository Pattern** separates the *data action layer* from *business logic*. Its goal is to make the Controller not care about *how* data is fetched from the database, but rather just call a method to get the data it needs. We encapsulate those queries inside a Repository class. Then your Controller becomes much cleaner (and adheres to the **DRY - Don't Repeat Yourself** principle): Use the Repository Pattern when: When your application evolves into a massive platform (enterprise / distributed system), placing all Models in `app/Models` and all Controllers in `app/Http/Controllers` will become chaotic and hard to navigate. **Domain-Driven Design (DDD)** shifts the mindset from being oriented around "framework technical folders" to being structured around **"Business Domains"**. Applications with DDD are grouped into independent modules or services within a directory, for example, `src/Domain`. Besides domain separation, DDD is tightly coupled with applying patterns such as **Value Objects**, **Data Transfer Objects (DTO)**, and **Action Classes** (*Service Classes* that execute the Single Responsibility principle / *SOLID*). Adopt the DDD architectural approach only if your application solves problems across distinctly different business domain ecosystems (*Bounded Contexts*) and is usually managed by cross-functional developer teams. It is not recommended to use DDD for simple projects with short deployment lifecycles. Working while adhering tightly to *Clean Architecture* principles is good, but forcing the use of Repository or DDD on every project, no matter how small, heavily violates the rule of efficiency. As a *Software Developer*, start by building the most relevant architecture you need right now, while keeping the door open to refactor your code as your application scales in the future!

Enjoyed this note?

There are more thoughts on software engineering, architecture, and developer workflows in the archive.

Back to all notes