Hexagonal Architecture in Python — Core Concepts
What Hexagonal Architecture is
Hexagonal Architecture was introduced by Alistair Cockburn in 2005 as a way to isolate application logic from external concerns. The formal name is Ports and Adapters. The central idea: your application exposes ports (interfaces) and external systems connect through adapters (implementations).
The three zones
The Application Core
Pure business logic. No knowledge of HTTP, SQL, message queues, or file systems. In Python, this means plain classes and functions — no framework imports.
Ports
Interfaces that define how the outside world interacts with the core. There are two types:
- Driving ports (primary) — how the outside world talks to your application. A use case interface is a driving port. The web controller “drives” the application by calling use cases.
- Driven ports (secondary) — how your application talks to the outside world. A repository interface is a driven port. Your application “drives” the database through this port.
Adapters
Concrete implementations that plug into ports:
- Driving adapters — FastAPI route handlers, CLI commands, message consumers. They receive external input and call driving ports.
- Driven adapters — SQLAlchemy repositories, HTTP API clients, email senders. They implement driven ports to connect to external systems.
How it differs from layered architecture
Traditional layered architecture (presentation → business → data) creates a linear dependency chain. Hexagonal architecture breaks this by making all external systems equally distant from the core. The database is not “below” the business logic — it is beside it, connected through a port, just like the web interface.
This symmetry is the key insight. Your application does not have a “top” and “bottom.” It has a center (core) and an outside (adapters).
A Python example
src/
core/
models.py # Domain entities
ports.py # Port interfaces (protocols)
services.py # Use cases
adapters/
driving/
api.py # FastAPI routes
cli.py # Click commands
driven/
postgres_repo.py # SQLAlchemy repository
stripe_pay.py # Stripe payment adapter
main.py # Wiring / composition root
The core/ directory has zero imports from adapters/. The adapters import from core/ports to know which interfaces to implement.
Why Python is well suited
Python’s structural typing through Protocol makes ports lightweight. You do not need to register adapters in a container or annotate them with decorators. If an object has the right methods, it satisfies the port — duck typing at its best.
Common misconception
“Hexagonal is just another name for Clean Architecture.” They are closely related but not identical. Hexagonal emphasizes the symmetry between driving and driven sides. Clean Architecture adds explicit layer rings (entities → use cases → adapters → frameworks). In practice, most Python projects blend ideas from both.
When to use it
Hexagonal Architecture pays off when:
- You expect to swap infrastructure (databases, payment providers, message brokers)
- Multiple entry points exist (API + CLI + worker)
- You want to test business logic without spinning up infrastructure
- The domain is complex enough to justify the structural investment
For a simple CRUD API with one database and one entry point, the overhead may not be worth it.
The one thing to remember: Hexagonal Architecture is about symmetry — every external system connects through the same kind of port, making your core logic independent of all of them equally.
See Also
- Python Aggregate Pattern Why grouping related objects under a single gatekeeper prevents data chaos in your Python application.
- Python Bounded Contexts Why the same word means different things in different parts of your code — and why that is perfectly fine.
- Python Bulkhead Pattern Why smart Python apps put walls between their parts — like a ship that stays afloat even with a hole in the hull.
- Python Circuit Breaker Pattern How a circuit breaker saves your app from crashing — explained with a home electrical fuse analogy.
- Python Clean Architecture Why your Python app should look like an onion — and how that saves you from painful rewrites.