Starting an Open-Source Project with DDD in Laravel: Folder Structure

3min read

I’m about to start a new project that already uses Domain-Driven Design (DDD). I’ve heard a lot about DDD, both the praise and the criticism, but never had the chance to use it. This feels like the perfect opportunity to finally learn it by doing. So I went through the basics, and now it’s time to put that knowledge into action.

The project I’m about to work on involves FFmpeg and video processing. Coincidentally, I’ve always had this idea of building an open-source alternative to Vimeo, or at least a simple platform where I could host and share my own videos. So I decided to use that idea as my playground.

The goal: a straightforward video hosting platform, aimed at agencies or professionals who need to share videos with clients or audiences.

The first challenge I ran into was folder structure. Laravel is an opinionated framework with a well-defined structure, so I wanted to find the right balance between sticking with Laravel’s conventions and applying DDD principles.

The most common approach that I’ve seen is GitHub is something like this:

├── app
│   ├── Http
│   ├── Models
│   ├── Providers
│   └── ...
│
├── ....
│
├── src
│   ├── Domains
│   ├── Application
│   ├── Infrastructure
│   └── Interfaces

In this approach, I’m keeping the default Laravel code inside the app folder as usual, while placing the rest inside a new src folder. But here’s where I got stuck: should components like Controllers live in app/Http/Controllers, following Laravel’s conventions, or should they go into something like src/Interfaces, staying closer to a “pure” DDD structure?

So the question is: how strictly we want to follow DDD principles in a Laravel project?

I started wondering if there were other possible solutions and with a little help from Claude, I ended up finding this folder structure as well:

app/
├── Http/                    # Presentation Layer
├── Console/                 # Presentation Layer  
├── Models/                  # Infrastructure Layer (data persistence)
├── Services/                # Application Layer
├── Actions/                 # Application Layer
├── Repositories/            # Infrastructure Layer (repository implementations)
├── Jobs/                    # Infrastructure Layer (queue implementations)
├── Domains/                  # Domain Layer
└── Providers/               # Infrastructure Layer (DI container config)

At first, this structure looked great to me, since It felt familiar. But there’s one clear problem: it mixes the presentation, infrastructure, and application layers all in one place.

That might be fine for small projects, but it misses the point of DDD. DDD really starts to make sense when the project is big, with lots of business rules and different kinds of logic that need to stay separate.

So that’s why I decided to stick with the first approach, but with a small twist:

├── app
│   ├── Http
│   ├── Models
│   ├── Providers
│   └── ...
│
├── ....
│
├── src
│   ├── Domains
│   ├── Application
│   ├── Infrastructure

This setup is mostly the same as before, but without the Interface layer. Why? Because instead of creating another set of Controllers inside src, I decided to just use Laravel’s existing Controllers as wrappers around the business domains.

For example, when someone uploads a video, Laravel’s routing and controllers handle the request and capture the data. From there, the controller calls the Video service inside the domain, which takes care of the business logic needed to process and upload the video.

So it would be something like this:

┌─────────────────────────────────────┐
│ LARAVEL WRAPPER (app/)              │
│                                     │
│ "Hey Laravel, someone wants to      │
│  upload a video via HTTP"           │
│                                     │
│ Controllers, Jobs, Commands         │
│ Requests, Resources, Middleware     │
└─────────────────┬───────────────────┘
                  │ Delegates to
                  ▼
┌─────────────────────────────────────┐
│ BUSINESS APPLICATION (src/)         │
│                                     │
│ "Here's how video uploading         │
│  actually works in our domain"      │
│                                     │
│ Domain, Application, Infrastructure │
└─────────────────────────────────────┘

In theory, this approach makes the business layer almost framework-agnostic. But since I plan to use Eloquent models inside my repositories, it’s still somewhat tied to Laravel.

That said, I think this is a solid starting point. It balances readability for Laravel developers while still staying close to DDD principles. the plan is to start here, see how it scales, and refine the structure as the project grows. If the codebase expands, I can always extract more layers or make the business logic fully independent.