Layered vs Hexagonal vs Clean vs Onion Architecture
Fast recall
Quick revision
Core answer
Understanding of the real goals of these patterns; recognizing they overlap heavily
Treating them as rigidly different; religious wars about terminology; over-engineering a simple CRUD app with clean architecture
Discuss the Dependency Inversion Principle as the core idea; why dependency direction matters; pragmatic blending; testability as the real payoff
Interview-ready guide
Interview answer
All four architectures are attempts to solve the same problem: decouple business logic from delivery mechanisms and infrastructure. They differ in vocabulary and emphasis, not fundamental goal.
The common goal
- Swap infrastructure without changing business logic
- Test business logic without spinning up Spring or databases
- Change UI or API without touching domain
- Express the domain in business language, not technical plumbing
The four approaches
Layered (N-tier) — the classic
- Controller, Service, Repository, Database
- Dependencies flow downward
- Simple, familiar, Spring Boot's default
- Weakness: doesn't enforce dependency inversion; services directly import JpaRepository, JavaMailSender
- Swapping infrastructure requires rewriting business layer
Hexagonal (Ports and Adapters) — Alistair Cockburn, 2005
- Domain at center
- Ports are interfaces the domain defines
- Adapters implement the ports
- Inbound adapters drive the domain (HTTP, CLI)
- Outbound adapters serve the domain (JPA, SMTP)
- Domain knows only ports; never adapters
Onion — Jeffrey Palermo, 2008
- Concentric rings: Entities, Domain Services, Application Services, Infrastructure
- Rule: dependencies point inward
- Very explicit diagram; essentially hexagonal with more layers
Clean Architecture — Uncle Bob, 2012
- Onion with explicit categories: Entities, Use Cases, Interface Adapters, Frameworks
- Same Dependency Rule as Onion
- More opinionated vocabulary
Are they really different?
- Hexagonal, Onion, Clean are substantially the same
- Core idea: business logic at center, dependencies point inward, infrastructure is a plugin
- Layered is the odd one out; doesn't invert dependencies
- In 2026, pick vocabulary (hexagonal is common in Spring Boot), follow Dependency Inversion Principle, stop debating terminology
The Dependency Inversion Principle is the real idea
- Business logic doesn't depend on infrastructure
- Both depend on abstractions (interfaces)
- The interfaces are owned by the business logic, not the infrastructure
When to pick each
Layered when
- Simple CRUD app
- Small team, single developer
- Less than 10 use cases total
- Business logic thin
- Speed over purity
Hexagonal when
- Domain has real business rules
- Multiple delivery mechanisms (REST + gRPC + scheduled job)
- Multiple infrastructure integrations
- Testing expensive with Spring/JPA
- Team practices DDD
Clean Architecture when
- Want explicit Use Case classes
- Mobile apps (Uncle Bob's original target)
- Regulated domains needing separation for audit
Common pitfalls
Anemic domain model
- Entities are just data holders; all logic in services
- Procedural thinking dressed up as OO
- Put behavior on entities: 'order.cancel()' not 'orderService.cancel(order)'
Leaky abstractions
- Domain port returns Spring Data Page type
- Fix: return domain List plus separate pagination metadata
Over-engineering CRUD
- 'Create user' with ports, adapters, DTOs, mappers
- 10 files for 10 lines of logic
- Stay layered when complexity doesn't warrant it
DI framework coupling in domain
- Putting @Service on domain class
- Domain now depends on Spring
- Plain classes; Spring config module wires them
DTO explosion
- RestDto, Command, Domain, Entity, ResponseDto all with mappers
- MapStruct helps but still boilerplate
- Use domain at boundaries where safe; mappers only where needed
Package structure matters
- Package by feature, not by technical layer
- com.example.order, not com.example.controllers
- Bounded contexts align with packages
Enforcement tools
- ArchUnit checks 'domain cannot import adapter classes' at test time
- Prevents drift in large teams
- Spring Modulith enforces module boundaries
Testing payoff is real
- Layered: unit tests need Spring context or heavy mocking
- Hexagonal: use cases unit-test with fake ports; no Spring, no DB; milliseconds
- Integration tests verify adapters separately
DDD alignment
- Layered: weak; CRUD-driven
- Hexagonal, Onion, Clean: excellent; aggregates, repositories, domain services fit naturally
Microservices and modular monoliths
- Each microservice is its own hexagonal mini-app
- Modular monolith: each module is hexagonal
- Modular monolith often better than microservices until organizational scale demands
The pragmatic recommendation
- Default to hexagonal for new microservices
- Stay layered for simple CRUD
- Don't argue about Hexagonal vs Clean vs Onion
- Enforce with ArchUnit
- Use DDD tactical patterns within whichever architecture
- Package by feature, not layer
The strategic answer
- All four share the same core idea: domain at center, infrastructure as plugin
- Pick vocabulary that fits your team
- Test independence is the real payoff
- Don't over-engineer simple apps; don't under-engineer complex ones
- Business logic that runs without Spring is the gold standard
Layered vs Hexagonal vs Clean vs Onion Architecture
Direct Answer
All four are attempts to decouple business logic from delivery and infrastructure — they share 90% of the philosophy and differ in emphasis: Layered (N-tier) is the classic controller→service→repository; dependencies flow downward; simplest but can't enforce 'domain doesn't know about DB'. Hexagonal (Ports & Adapters, Alistair Cockburn) puts domain at center; ports define contracts, adapters implement them; very explicit about inbound vs outbound dependencies. Onion (Jeffrey Palermo) is hexagonal with explicit concentric rings; dependencies point inward; domain model at core. Clean Architecture (Uncle Bob) is onion with more opinionated layers (Entities, Use Cases, Interface Adapters, Frameworks) and the Dependency Rule. In practice, Hexagonal and Clean are near-identical; pick one vocabulary and stop debating; layered is fine for small CRUD apps.
Common Mistakes & Pitfalls
Treating them as rigidly different; religious wars about terminology; over-engineering a simple CRUD app with clean architecture
Check your understanding
Answer these without looking back at the article.
- What is the Dependency Inversion Principle and how does it relate to these architectures?
- How would you enforce architectural boundaries with ArchUnit in Spring Boot?
- What's the difference between anemic and rich domain models?
- When does a modular monolith make more sense than microservices?
Related interview prep categories
1Want a guided curriculum order?
These modules are also sequenced in our flagship backend interview track — open it when you prefer an ordered path instead of browsing by topic.