main difference between domain-driven design and clean architecture is we are seperating business login, infrastructure and presentation layer for individual module in domain-driven design(DDD).
where seperating business login, infrastructure and presentation layer onces for all module in clean architecture.
Here’s a simplified folder structure comparing Domain-Driven Design (DDD) and Clean Architecture, ensuring clarity and scalability while reducing unnecessary depth.
let take an example for creating folder structure for user and blog module...
Domain-Driven Design (DDD)
src/
├── modules/ # Feature-based modules
│ ├── user/ # User module
│ │ ├── application/ # Use cases (business logic)
│ │ │ ├── create-user.usecase.ts
│ │ │ └── update-user.usecase.ts
│ │ ├── domain/ # Core business logic
│ │ │ ├── user.entity.ts
│ │ │ ├── user.repository.ts
│ │ │ └── user.validator.ts
│ │ ├── infrastructure/ # Data access and persistence
│ │ │ ├── user.repository.impl.ts
│ │ │ └── prisma.service.ts
│ │ ├── interfaces/ # Controllers, APIs, and DTOs
│ │ │ ├── user.controller.ts
│ │ │ ├── create-user.dto.ts
│ │ │ └── update-user.dto.ts
│ │ └── user.module.ts # Module setup
│ ├── blog/ # Blog module
│ │ ├── application/
│ │ ├── domain/
│ │ ├── infrastructure/
│ │ ├── interfaces/
│ │ └── blog.module.ts
├── shared/ # Shared utilities and services
│ ├── exceptions/
│ │ └── custom-error.ts
│ ├── utils/
│ │ └── logger.service.ts
├── main.ts # Entry point
└── app.module.ts # Root application module
Clean Architecture
src/
├── core/ # Core application logic
│ ├── usecases/ # Application use cases
│ │ ├── create-user.usecase.ts
│ │ ├── update-user.usecase.ts
│ │ ├── create-blog.usecase.ts
│ │ └── update-blog.usecase.ts
│ ├── entities/ # Domain models/entities
│ │ ├── user.entity.ts
│ │ ├── blog.entity.ts
│ │ └── index.ts
│ ├── repositories/ # Repository interfaces
│ │ ├── user.repository.ts
│ │ ├── blog.repository.ts
│ │ └── index.ts
│ └── validators/ # Domain-level validations
│ ├── user.validator.ts
│ ├── blog.validator.ts
│ └── index.ts
├── adapters/ # Adapters for data and frameworks
│ ├── database/ # Database layer
│ │ ├── prisma/
│ │ │ ├── schema.prisma
│ │ │ ├── prisma.service.ts
│ │ │ └── user.repository.impl.ts
│ │ └── blog.repository.impl.ts
│ └── controllers/ # Controllers (API endpoints)
│ ├── user.controller.ts
│ ├── blog.controller.ts
│ └── index.ts
├── config/ # Configuration files
│ └── app.config.ts
├── shared/ # Shared utilities
│ ├── exceptions/
│ │ └── custom-error.ts
│ ├── utils/
│ │ └── logger.service.ts
│ └── index.ts
├── main.ts # Entry point
└── app.module.ts # Root application module
Choose DDD if the application is domain-complex and feature-based, or Clean Architecture if you want to prioritize clear separation of layers. Let me know which one resonates!
want to know more about me, just write sallbro on search engine...
Top comments (1)
Clean Architecture has a single rule: dependencies must always point toward the domain.
Many NestJS projects violate this rule, even those that claim to use Clean Architecture.
NestJS has a key feature that is often misused and ends up breaking the dependency rule.
That same feature, when used correctly (as shown in the documentation), allows the rule to be respected without hacks.
The key is to properly understand the rule and know what to do and what not to do. The documentation explains how to apply the correct option.
There are four strategies to implement transaction management in a NestJS project that uses Clean Architecture.
One of these strategies relies on a feature that has existed since Node.js 12.
Each strategy can be analyzed in terms of: