Skip to content

Hexagonal architecture (ports and adapters)

Hexagonal architecture, also called ports and adapters, puts the application’s business logic at the center and keeps everything technical (web frameworks, databases, message brokers, third-party APIs) at the edges. The core defines ports: interfaces describing what it needs and what it offers. Adapters implement those ports for a specific technology.

Clean architecture and onion architecture are close relatives built on the same idea: dependencies point inward, toward the business rules.

flowchart LR
    rest[REST adapter] --> inport([Inbound port])
    cli[CLI adapter] --> inport
    subgraph core [Application core]
        inport --> logic[Business logic]
        logic --> outport1([Repository port])
        logic --> outport2([Payment port])
    end
    outport1 --> pg[Postgres adapter]
    outport2 --> stripe[Payment provider adapter]
  • The core knows nothing about technology. No framework annotations, SQL or HTTP in the business logic.
  • Inbound (driving) ports describe what the application can do, e.g. PlaceOrder. Adapters such as REST controllers or message listeners call them.
  • Outbound (driven) ports describe what the application needs, e.g. OrderRepository. Adapters such as a database client implement them.
  • Dependencies point inward. Adapters depend on the core; the core never depends on adapters.
  • Business logic is easy to test: swap real adapters for in-memory ones and test without databases or servers.
  • Technology can change: replacing a database or framework touches only one adapter.
  • Clear intent: the ports document exactly what the application does and depends on.
  • Delays technology decisions: the core can be built before the database is chosen.
  • More code: interfaces and mapping between core models and adapter models add boilerplate.
  • Overkill for simple applications: a basic data-entry app gains little from the extra indirection.
  • Learning curve: teams used to framework-first code need time to adjust.
  • Domains with rich, valuable business rules that should outlive today’s frameworks.
  • Systems that integrate with many external services or may switch providers.
  • Teams that want fast, reliable unit tests of business behavior.
  • Thin CRUD applications whose logic is mostly moving data between screens and tables. A layered architecture is simpler.
  • Short-lived prototypes.
  • Framework types leaking into the core, such as ORM entities or HTTP request objects used as domain models.
  • Ports that mirror the technology. A port named JdbcOrderDao defeats the purpose; name ports after business needs.
  • One port per class. Group ports by capability, not by individual method, to avoid an explosion of tiny interfaces.

Glossary: domain-driven design

  • Alistair Cockburn, “Hexagonal Architecture” (original article, alistair.cockburn.us)
  • Robert C. Martin, Clean Architecture

Written and edited by Abhinav Taduka, enterprise software architect.