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 infrastructureadaptersuse_casesdomain, 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.

pythonarchitectureclean-code

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.