Clean Architecture in Python — Core Concepts
What Clean Architecture is
Clean Architecture, popularized by Robert C. Martin, organizes code into concentric layers where dependencies point inward. Inner layers define business rules; outer layers handle infrastructure. The core idea is the Dependency Rule: source code dependencies must always point toward higher-level policies.
The four layers
Entities (innermost)
Enterprise-wide business rules. In Python, these are plain classes or dataclasses that represent domain concepts — Order, Customer, Invoice. They have no imports from frameworks, databases, or external libraries.
Use Cases
Application-specific business rules. A use case orchestrates entities to accomplish a goal: “place an order,” “generate a monthly report.” Each use case is typically one class or function with a single public method.
Interface Adapters
Translators between the use cases and the outside world. Controllers, presenters, and repository implementations live here. A FastAPI route handler is an adapter — it converts an HTTP request into a use case call and formats the response.
Frameworks and Drivers (outermost)
Database engines, web frameworks, message queues, external APIs. This layer contains configuration and glue code. It is the most volatile and the least important to your business logic.
How dependencies flow
The critical rule: inner layers never import from outer layers. An entity never imports SQLAlchemy. A use case never imports FastAPI. Instead, inner layers define interfaces (protocols or abstract base classes) that outer layers implement.
Frameworks → Adapters → Use Cases → Entities
↑ ↑
└── dependencies always point ──────┘
INWARD
Why it matters for Python projects
Python projects often start with framework-first thinking — “it is a Django app” or “it is a Flask app.” Clean Architecture flips this: the framework is a detail, not the foundation.
Benefits:
- Testability — Business logic is tested without databases or HTTP.
- Framework independence — Switch from Flask to FastAPI without rewriting use cases.
- Clarity — New developers understand what the system does by reading use cases, not route handlers.
Common misconception
“Clean Architecture means lots of boilerplate.” In Java, yes, the interface and implementation ceremony adds weight. Python’s protocols and duck typing reduce this significantly. A use case can depend on a Readable protocol, and any object with a get() method satisfies it — no registration, no XML, no DI container required.
A typical Python project structure
src/
domain/ # Entities and value objects
use_cases/ # Application logic
adapters/ # Repository implementations, API controllers
infrastructure/ # Database config, framework setup, external clients
Each directory maps to a layer. Imports flow from infrastructure → adapters → use_cases → domain, never the reverse.
The one thing to remember: Clean Architecture is about making your business rules the center of gravity so that everything external — databases, frameworks, UIs — can be replaced without touching the core.
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 Connection Draining How to shut down a Python server without hanging up on people mid-conversation — like a store that locks the entrance but lets shoppers finish.