open atlas
↑ Back to track
Architecture Patterns ARCH · 05 · 01

The concentric dependency rule

Clean and Onion architecture arrange layers as concentric circles. The one absolute rule: source-code dependencies point inward only, toward higher-level policy. This generalizes hexagonal's two-sided inversion to any number of rings.

ARCH Middle ◷ 22 min
Level
FoundationsJuniorMiddleSenior

The B2B order platform had grown into a four-layer stack: presentation, application, domain, infrastructure. The team had read about hexagonal architecture and carefully placed interfaces at every boundary. But six months in, they found something wrong: the domain layer was importing from the infrastructure layer to get at a shared utility for formatting money values. The utility lived in infrastructure because it had been put there alongside the database currency-conversion code. The interface boundaries were intact — the domain called an interface, not a concrete class — but the interface itself was defined inside the infrastructure package, which meant the domain depended on infrastructure’s package for the interface definition. The dependency inversion was incomplete. The interface existed but the domain did not own it. When Clean Architecture was published in 2017, Robert Martin was not proposing something entirely new. He was taking the core insight of hexagonal architecture — ports owned by the application — and systematizing it into a rule that applied to every layer boundary, not just the domain/infrastructure divide. The rule he stated was precise: source-code dependencies can only point inward — toward higher-level policy.

The concentric-circle model

Both Clean Architecture (Robert Martin, 2012 blog post, 2017 book) and Onion Architecture (Jeffrey Palermo, 2008) organize a system as a set of concentric circles — rings nested inside each other, with the most important and stable code at the center and the most volatile, infrastructure-specific code at the outer edge.

The rings differ slightly between the two models, but the logic is the same. Martin’s canonical four rings are:

  1. Entities (innermost) — enterprise-wide business rules; the most stable code in the system.
  2. Use Cases — application-specific business rules; orchestrate entities to achieve goals.
  3. Interface Adapters — translate between the use-case format and the outside world (controllers, presenters, gateways).
  4. Frameworks and Drivers (outermost) — web frameworks, databases, external libraries; the most volatile code.

Palermo’s Onion uses slightly different names but the same logic: the Domain Model at the center, then Domain Services, then Application Services, then the outer Infrastructure ring. Both models arrive at the same structural constraint.

The dependency rule — why it is a rule, not a guideline

The single enforced constraint is: a source-code dependency (import, reference, compilation dependency) may only point inward. Nothing in an inner ring can name anything in an outer ring. An entity cannot import a use case. A use case cannot import a controller. An interface adapter cannot import the web framework — the web framework imports the adapter.

This is not a principle of style. It is a structural constraint with a specific payoff: if nothing in the inner rings knows about the outer rings, the inner rings can be compiled, tested, and reasoned about in complete isolation from infrastructure. You can run all your entity and use-case tests without a database, a web server, or an ORM being present.

The violation in the opening story — the domain importing a money-formatting utility from the infrastructure package — broke this rule. Even though an interface was involved, the domain had to import the interface from the infrastructure package to use it. The import path crossed the boundary in the wrong direction. The fix is the same as in hexagonal: move the interface into the inner ring (the domain defines it), and let the outer ring implement it.

Why this works

Why does stability increase toward the center? Inner rings contain pure business logic: the rules that change only when the business model itself changes. Outer rings contain technology choices: databases, frameworks, protocols — these change for technology reasons (a new ORM version, a cloud provider change, a third-party API deprecation) that have nothing to do with business logic. By structuring dependencies to point toward the stable center, you ensure that technology changes cannot force business-logic changes. The database can be replaced without rewriting a use case. A web framework upgrade cannot require an entity change. Stability and abstraction correlate: the innermost code is the most abstract (pure business rules, no technology detail) and the most stable; the outermost is the most concrete and the most volatile.

How Clean Architecture generalizes hexagonal

Unit 04 introduced hexagonal architecture: ports owned by the application, adapters on both sides. Clean and Onion architecture generalize this from a single boundary (domain / infrastructure) to N concentric boundaries.

In hexagonal, the inversion happens once: the domain defines the port interfaces; infrastructure implements them; the dependency arrow points inward. Clean and Onion apply the same inversion at every ring boundary. The Interface Adapters ring defines the interfaces that Frameworks & Drivers must implement (exactly as the domain defined secondary ports in hexagonal). The Use Cases ring defines the interfaces (output ports, presenter interfaces) that the Interface Adapters ring must implement. The inversion propagates all the way in.

Clean vs Onion — the overlap and the difference

Clean Architecture and Onion Architecture are independently conceived but structurally convergent. Both arrived at the same dependency rule. The practical differences are:

Onion Architecture (Palermo, 2008) emphasizes the Domain Model as the absolute center — pure domain objects with no dependencies. It puts Domain Services in the next ring, Application Services next, and Infrastructure at the outside. The emphasis is on the domain model being free from all infrastructure and application concerns.

Clean Architecture (Martin, 2012/2017) labels the rings differently and places an explicit Interface Adapters ring that is responsible for all data format translation between the use-case world and the outside world. It also distinguishes Entities (enterprise-wide rules, potentially shared across apps) from Use Cases (application-specific rules).

In practice, teams often conflate the two or use a hybrid. The important thing is not which ring names you use — it is whether you enforce the dependency rule. A codebase that calls itself “Clean Architecture” but has use cases importing framework classes violates the rule regardless of the diagram on the whiteboard.

lesson.inset.note

The concentric model is not a fixed number of rings. Martin explicitly states the diagram with four rings is illustrative; real systems might have more. What is non-negotiable is the direction of dependency — inward only — and the principle of ownership: the inner ring defines the interface; the outer ring implements it. You can add an Anti-Corruption Layer ring, a Reporting ring, an External Services ring — as long as every new ring’s dependencies point inward, the architecture is valid.

Quiz

The B2B platform's Use Cases ring imports a CurrencyFormatter interface from the Infrastructure ring because that is where the money-formatting utility was originally written. The interface has no infrastructure-specific methods — it is pure. Is this a violation of the dependency rule, and why?

Quiz

A team wants to add a PDF report generation ring outside the Interface Adapters ring, between Interface Adapters and Frameworks. The PDF library is a third-party vendor package. Where should the PDF ring's interfaces be defined, and which ring should implement them?

Quiz

An Onion Architecture codebase has this structure: Domain Model → Domain Services → Application Services → Infrastructure. A developer says: 'Onion and hexagonal are the same thing — both just put an interface between the domain and the database.' What is missing from this description?

Recall before you leave
  1. 01
    What is the dependency rule in Clean Architecture, and why does it produce independently testable inner rings?
  2. 02
    How does Clean Architecture generalize hexagonal architecture?
  3. 03
    What is the structural difference between Onion Architecture and Clean Architecture?
Recap

Clean and Onion architecture are concentric-ring models that generalize hexagonal architecture’s core insight to every layer boundary. The architectural center holds the most stable, abstract code — pure business rules that change only when the business itself changes. The outer rings hold technology choices — databases, frameworks, protocols — that change for technology reasons unrelated to business logic.

The dependency rule states this precisely: source-code dependencies may only point inward. An inner ring may never import from an outer ring. The inner ring defines the interface; the outer ring implements it. Every ring boundary applies this inversion.

The opening story’s violation — a Use Cases ring importing an interface from the Infrastructure package — was technically subtle: there was an interface, there was no concrete import. But the interface definition lived in the wrong ring, and the Use Cases ring had an import path pointing outward. The fix is ownership: move the interface into the ring that consumes it.

Clean Architecture (Martin) and Onion Architecture (Palermo) differ mainly in ring names and emphasis. Both arrive at the same structural rule. The number of rings is not fixed at four — systems add rings as needed. What is non-negotiable is the direction: inward only.

The next lesson examines what lives at the second ring — the Use Cases ring — and how the interactor pattern captures “what the application does” as a first-class structural unit.

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 4 done

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

Apply this

Put this lesson to work on a real build.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.