Hexagonal Architecture
In short
Hexagonal architecture is a way of structuring software so the core business logic talks to the outside world only through ports and swappable adapters.
What is hexagonal architecture?
Hexagonal architecture, also called ports and adapters, was described by Alistair Cockburn in 2005. It places the application's core, the business rules, at the center and treats everything else, such as databases, web frameworks, message queues, and third-party APIs, as external details. The core never depends on those details directly; they plug into it.
The core defines ports, which are interfaces describing what it needs or offers, for example an OrderRepository with a save method or a PaymentGateway with a charge method. Adapters are the concrete implementations that connect a port to a specific technology: a SQL database adapter, an in-memory adapter for tests, a REST controller, or a command-line interface. Driving adapters, such as an HTTP controller, call into the core, while driven adapters, such as a database repository, are called by the core.
Think of a laptop with standard ports like USB-C and HDMI. The laptop doesn't care which monitor or keyboard you plug in, as long as the device fits the port. In the same way, you can swap a real database for an in-memory fake in unit tests, or replace one email provider with another, without touching the business logic.
Hexagonal architecture is often confused with layered architecture and clean architecture. A classic layered design stacks presentation, business, and data layers, and the business layer often depends directly on the data layer, while hexagonal architecture inverts that dependency with interfaces so all dependencies point inward toward the core. Clean architecture and onion architecture build on the same idea with more named rings, so they are close relatives rather than competitors. The hexagon shape itself has no special meaning; it just leaves room to draw several ports.
Key takeaways
- Business logic sits at the center and knows nothing about frameworks or databases.
- Ports are interfaces defined by the core; adapters implement them for specific technologies.
- All dependencies point inward toward the core.
- Swapping adapters makes testing with fakes and changing technologies easier.
- It is closely related to clean architecture and relies on dependency inversion.
Example
type Order = { id: string; total: number };
// Port: defined by the core, knows nothing about databases
interface OrderRepository { save(order: Order): Promise<void>; }
// Core logic depends only on the port
async function placeOrder(repo: OrderRepository, order: Order) {
if (order.total <= 0) throw new Error("Order total must be positive");
await repo.save(order);
}
// Adapter: one concrete implementation, easy to swap for a SQL version
class InMemoryOrderRepository implements OrderRepository {
orders: Order[] = [];
async save(order: Order) { this.orders.push(order); }
}Readers ask
Why is it called hexagonal architecture?
The name comes from the diagram Alistair Cockburn used, with the application drawn as a hexagon and ports on its sides. The number six has no meaning; the shape just leaves room for several ports and adapters.
What is the difference between hexagonal architecture and clean architecture?
Both keep business logic independent of frameworks and make dependencies point inward. Hexagonal architecture focuses on the core plus ports and adapters, while clean architecture adds more named layers, such as entities and use cases, inside the core.
When is hexagonal architecture worth it?
It pays off for applications with meaningful business logic that should outlive specific frameworks, databases, or integrations, and that need strong automated tests. For a small script or a simple CRUD app, the extra interfaces may add more ceremony than value.
See also
- Clean ArchitectureSoftware Architecture, p. 5Clean architecture is a way of structuring software in layers so that the core business rules never depend on frameworks, databases, or user interfaces.
- Dependency InjectionSoftware Architecture, p. 12Dependency injection is a design technique in which an object receives the other objects it needs from the outside instead of creating them itself.
- Separation of ConcernsSoftware Architecture, p. 37Separation of concerns is a design principle that divides a program into distinct parts, each responsible for one clearly defined aspect of its behavior.
- Domain-Driven DesignSoftware Architecture, p. 15Domain-driven design is an approach to building software that models the code closely on the business domain, using the same language as the domain experts.
- Loose CouplingSoftware Architecture, p. 26Loose coupling is a design principle in which components depend on each other as little as possible, so one can change without breaking the others.
- InterfaceProgramming Fundamentals, p. 29An interface is a named set of method and property signatures that a type promises to provide, without saying how those members are implemented.
Spotted a mistake or something missing on this page?Suggest an edit