Onion Architecture

Concentric layers with the domain model at the center; dependencies point inwards and infrastructure sits at the edge.

Context

Proposed by Jeffrey Palermo in 2008, before Clean Architecture. It starts from a critique of classic layered architecture: the domain ended up depending on the data layer, so the database was the real center of the system.

Problem

In a traditional layered architecture (UI → Business → Data), the business layer references data access. Changing the ORM or testing business logic without a database becomes costly.

Solution

Concentric layers with a single rule: code can only depend on inner layers.

┌───────────────────────────────────────────────┐
│  UI · Infrastructure · Tests                  │  ← Outer (details)
│  ┌─────────────────────────────────────────┐  │
│  │  Application services                   │  │
│  │  ┌───────────────────────────────────┐  │  │
│  │  │  Domain services                  │  │  │
│  │  │  ┌─────────────────────────────┐  │  │  │
│  │  │  │  Domain model               │  │  │  │  ← Center
│  │  │  │  (entities, value objects)  │  │  │  │
│  │  │  └─────────────────────────────┘  │  │  │
│  │  └───────────────────────────────────┘  │  │
│  └─────────────────────────────────────────┘  │
└───────────────────────────────────────────────┘
  1. Domain model (center): entities and value objects, no dependencies.
  2. Domain services: rules that do not belong to a single entity. Repository interfaces live here too.
  3. Application services: orchestrate use cases.
  4. Outside: UI, persistence, external services and tests. They implement the interfaces defined inwards.

#Typical .NET structure

CSHARP
src/
├── Core/
│   ├── Domain/          ← Entities, value objects, repository interfaces
│   └── Application/     ← Application services, DTOs
├── Infrastructure/      ← EF Core, HTTP clients, messaging
└── Web/                 ← API/UI, DI composition

#What sets it apart

  • It is the one that most emphasizes the domain model as the center and the split between domain and application services.
  • Less prescriptive than Clean: no "interface adapters" layer and no rules on how data travels between layers.
  • More structured than Hexagonal: it defines internal layers, not just inside/outside.
  • In practice, many .NET templates called "Clean Architecture" are strictly Onion: Domain, Application, Infrastructure, Web.

See the full comparison.

When NOT to use it
  • CRUD applications without a rich domain.
  • If the team can't tell a domain service from an application service: layers become folders with no meaning.
Tradeoffs
Pro Con
Domain independent of persistence More projects and mappings
Strong alignment with DDD The domain service / application service boundary confuses
Testable without infrastructure Same idea as Hexagonal/Clean with different vocabulary: easy to over-debate names

#architecture #onion #ddd