Hexagonal Architecture
Hexagonal architecture protects the core domain from external systems by using ports and adapters.
Core Idea
Also known as Ports & Adapters, hexagonal architecture places the domain logic at the center of the application. External concerns — databases, APIs, user interfaces, message queues — connect to the domain through well-defined ports (interfaces) and adapters (implementations). The domain never depends on infrastructure; infrastructure depends on the domain.
Inbound Adapters
Outbound Adapters
Ports
Ports are interfaces defined by the domain that describe what capabilities it needs (outbound ports) or what operations it exposes (inbound ports). They are technology-agnostic and expressed in domain language.
- Inbound ports: Define the use cases the application supports (e.g.,
PlaceOrder,RegisterUser) - Outbound ports: Define what the domain needs from the outside world (e.g.,
OrderRepository,PaymentGateway)
Adapters
- Inbound adapters: Translate external requests into domain operations. Examples: HTTP controllers, GraphQL resolvers, message consumers, CLI commands.
- Outbound adapters: Implement outbound ports using specific technologies. Examples: SQL repositories, REST clients, SMTP email senders, file system storage.
Benefits
- Domain isolation: The domain logic is free from infrastructure concerns and can evolve independently
- Testability: The domain can be tested without any infrastructure by using in-memory adapters
- Flexibility: Infrastructure components can be swapped without changing domain logic
- Explicit boundaries: The ports make dependencies visible and intentional
- Multiple entry points: The same domain logic can be accessed via HTTP, CLI, events, or tests
Trade-offs
- Indirection: More interfaces and mapping code than a direct approach
- Over-engineering risk: For simple CRUD applications, the extra structure may not pay for itself
- Learning curve: Teams unfamiliar with the pattern may struggle with where to place code
- Mapping overhead: Data must be translated between adapter models and domain models at every boundary
Common Mistakes
- Domain depending on infrastructure: The most critical violation — if the domain imports from an adapter package, the architecture is broken
- Anemic ports: Creating ports that mirror database tables rather than expressing domain concepts
- Adapter leakage: Letting adapter-specific types (ORM entities, HTTP request objects) flow into the domain
- Too many ports: Creating a separate port for every method rather than grouping related operations
Relation to Clean Architecture
Clean Architecture (Robert C. Martin) shares the same core principle: dependencies point inward toward the domain. Clean Architecture adds more explicit layers (entities, use cases, interface adapters, frameworks) but the fundamental insight is identical — protect the domain from external change.
Hexagonal architecture tends to be more pragmatic in practice, with fewer prescribed layers and more emphasis on the port/adapter mechanism itself.