---
title: "Hexagonal, clean, onion, ports-and-adapters architecture"
chapter: "09"
---

# Hexagonal, clean, onion, ports-and-adapters architecture

These related styles put business policy inside and volatile delivery or infrastructure details outside. Dependencies point toward stable policy; ports express required or offered capabilities; adapters connect technology.

## Core ideas and patterns

| Idea | What it solves | Cost, limit, or warning |
|---|---|---|
| **Hexagonal architecture** | Separates application core from external actors | Too many generic ports can obscure the domain |
| **Clean architecture** | Organizes dependency direction around entities and use cases | Rigid rings can create ceremony |
| **Onion architecture** | Places domain model at the center of dependency layers | Does not decide distributed boundaries |
| **Inbound port** | Defines an application use case | A CRUD-shaped port can leak persistence thinking |
| **Outbound port** | Expresses a capability the core requires | One port per library call over-abstracts stable tools |
| **Adapter** | Translates HTTP, messaging, persistence, or provider protocols | Adapters must preserve semantics, not only syntax |

## How to apply it

Model use cases and invariants without framework types. Define ports in domain language. Build adapters for REST, CLI, messages, databases, clocks, identity, and suppliers. Keep transactions and authorization at the boundary that owns the rule. Use dependency inversion only where substitution, isolation, or testing matters.

## Evidence, not opinion

Compile the core without infrastructure frameworks. Run the same use-case tests through in-memory and real adapters. Use contract tests to verify semantic equivalence. Check that framework annotations do not leak into central policy unnecessarily.

## Small example

A TransferFunds use case depends on AccountRepository, ExchangeRate, Clock, and Audit ports. PostgreSQL, a bank API, and Kafka are adapters; none defines the transfer invariant.

## Feynman check

Explain the design to a new engineer without using the pattern names. State the
problem, the forces that conflict, the chosen boundary or mechanism, what can
fail, and the evidence that would prove the choice still works.
