Clean architecture

On this page 7

Clean architecture is a software architecture style, popularized by Robert C. Martin in 2012, that organizes a system into concentric layers and requires that source code dependencies point only inward, toward the business rules. The core of the application, its entities and use cases, therefore knows nothing about frameworks, databases, web servers or user interfaces.

In software architecture, clean architecture consolidates several earlier ideas, notably hexagonal architecture (ports and adapters) and onion architecture, into one set of rules. Its goal is a codebase in which business logic can be tested without infrastructure and in which technical details such as the database or the web framework can be replaced with limited impact on the core.

The layers of clean architecture

Clean architecture is usually drawn as four concentric circles, from the most stable and abstract policies at the center to the most volatile technical details at the edge. The number of circles is not fixed, but the direction of dependencies is.

LayerContainsDepends onChanges when
EntitiesEnterprise business rules and core dataNothingFundamental business policy changes
Use casesApplication-specific workflowsEntitiesA feature or process changes
Interface adaptersControllers, presenters, gateways, mappersUse casesData formats or API shapes change
Frameworks and driversWeb framework, database, UI, devicesInterface adaptersTechnology choices change
Typical layers from the center outward

Entities encapsulate rules that would exist even without software, such as how interest is calculated on a loan. Use cases, also called interactors, orchestrate entities to fulfill one application goal, such as approving a loan application. The outer layers merely translate between the core and the outside world.

The dependency rule and boundary crossing

The defining principle is the dependency rule: nothing in an inner circle may name anything declared in an outer circle, including classes, functions, variables and data formats. A use case may not import an ORM model, an HTTP request object or a framework annotation.

Control flow, however, often runs outward, for example when a use case must save data. Clean architecture solves this with the dependency inversion principle: the use case layer declares an interface, often called a port or repository interface, and the outer layer provides an implementation. At startup, a composition root or a dependency injection container wires the concrete implementation into the use case.

Data crossing a boundary should take the form most convenient for the inner layer, typically simple request and response models. Passing database rows or framework objects inward would quietly reintroduce the coupling the architecture is meant to prevent.

Clean architecture belongs to a family of dependency-inverted architectures and is frequently compared with the traditional layered model and with microservices. The table clarifies the differences.

StyleCentral ideaDependency directionScope
Layered architecturePresentation, business, data tiersDownward toward the databaseInside one application
Hexagonal architecturePorts and adapters around the coreInward toward the domainInside one application
Onion architectureDomain model at the centerInward toward the domainInside one application
Clean architectureEntities and use cases at the centerInward, explicit dependency ruleInside one application
MicroservicesIndependently deployable servicesBetween services via APIsAcross a whole system
Clean architecture versus neighboring architecture styles

The decisive difference from classic layering is that the database becomes a detail rather than the foundation. Clean architecture and microservices are complementary: each microservice can be built internally with clean architecture, while the microservice style governs how services relate to one another.

Applying clean architecture in practice

Implementations usually express the layers as separate modules or packages so that the build system, not only code review, prevents forbidden imports. Common practical techniques include the following.

  • One use case class per business action, such as PlaceOrder or CancelSubscription, with a single public method.
  • Repository interfaces declared in the core and implemented in an infrastructure module.
  • Plain request and response models at boundaries instead of framework types.
  • Architecture tests with tools such as ArchUnit or import linters that fail the build on dependency violations.
  • Organizing packages by feature, so the structure reveals what the system does rather than which framework it uses.

The payoff is most visible in testing: use cases can be exercised with in-memory fakes in milliseconds, without starting a server or database. Infrastructure adapters then receive their own focused integration tests.

Costs, limits and common mistakes

Clean architecture adds indirection and boilerplate: interfaces, mappers and data transfer objects that a small application may not need. Its benefits grow with the lifetime and business complexity of the system, so applying it to a short-lived prototype or a simple data-entry tool is often over-engineering.

MistakeConsequenceBetter approach
Framework annotations on entitiesCore coupled to infrastructureMap to persistence models in adapters
Interfaces for every classNeedless indirectionAbstract only real boundaries
Anemic use cases that only forward callsLayers without valueMerge layers in simple features
Mapping the same data many timesSlow development, duplicationShare stable models where safe
Folder names without enforced rulesDependency rule silently brokenModule boundaries and architecture tests
Frequent clean architecture mistakes

A pragmatic rule is to apply the full structure where the business logic is rich and to accept a thinner design for simple create, read, update and delete areas, while still keeping the dependency direction intact.

A non-technical view

Think of a restaurant whose recipes are written down independently of the kitchen equipment. The recipes are the heart of the business. Ovens, delivery apps and payment terminals can be replaced, and the recipes stay the same.

Clean architecture organizes software the same way. The rules that describe the business sit at the center and do not depend on any particular technology. Technology plugs in from the outside, so it can be swapped without rewriting what makes the business unique.

A concrete example

An insurance company builds a claims processing service. The core module contains entities such as Policy and Claim and use cases such as SubmitClaim and AssessClaim, which apply coverage limits and deductibles. The core declares a ClaimRepository interface and a FraudCheck port but imports no framework or database library.

Three years later, the company moves from a relational database to a managed document store and replaces its in-house fraud engine with an external scoring service. The team writes two new adapters and changes the wiring in the composition root, while the use cases and their roughly 600 unit tests remain untouched. The migration finishes in weeks rather than months because the business rules never depended on the replaced technology.