Contents

Architecture & System Design › Architecture Styles

Hexagonal Architecture

Ports and adapters that isolate core logic from infrastructure.

Also known as: hexagonal architecture, ports and adapters, ports adapters

Hexagonal architecture (ports and adapters) isolates the application core behind ports (interfaces it defines: “I need persistence,” “I publish events”) with adapters plugging in implementations (Postgres, Kafka, REST). The core never imports infrastructure; infrastructure adapts to the core’s contracts. Testability and replaceability follow structurally.

core (domain + use cases) ← ports (interfaces core owns)
adapters (DB, queue, HTTP, UI) implement ports from outside

The inversion matters: traditional layering lets infrastructure concerns seep inward (ORM annotations on entities, HTTP types in services); hexagons forbid it — adapters translate at the boundary, and the core compiles against nothing external.

The classic mistakes:

  • Ports owned by infrastructure. Interfaces shaped by frameworks (repository interfaces mirroring ORM quirks) invert the inversion. Ports express core needs in domain language.
  • Leaky adapters. ORM entities, HTTP statuses or queue semantics escaping into the core defeat the boundary. Translate fully at adapters; core types stay pure.
  • Port explosion. An interface per method fragments the boundary into noise. Cohesive ports (persistence, notification, clock) at sensible granularity.
  • Testing only through adapters. Spinning databases to test business rules wastes the isolation ports provide. Test the core directly against in-memory fakes; test adapters separately.
  • Framework-shaped cores. Entities decorated with persistence annotations, validation tied to HTTP libraries — infrastructure in domain clothing. Strip frameworks from the centre.
  • Adapter logic creep. Business decisions migrating into mappers and controllers (“discount if premium”) bypass tested cores. Adapters translate; cores decide.
  • Hexagons for CRUD. Simple data-shuttling apps gain ceremony without decisions to protect. Apply where domain complexity justifies the boundary.

When to adopt: domain-rich applications with changing infrastructure — the core’s longevity exceeds any adapter’s. Ports protect decisions; adapters absorb change.