Stackbook Logo
architecture-descriptionestablished · low operational burden

Clean Architecture

Also known as: onion-architecture, concentric-layers

Intent

Organize code in concentric layers where source dependencies only point inward toward business rules.

Problem

Frameworks, UIs, and databases dictate the shape of code, making business rules hard to test and expensive to migrate. Changes in outer technology ripple into core logic.

Forces

  • •Business rules change for different reasons than frameworks
  • •Fast automated tests require independence from I/O
  • •Teams need a shared, enforceable structure
  • •Strict layering adds mapping boilerplate

Solution

Overview

Clean architecture, popularized by Robert C. Martin, unifies earlier ideas such as hexagonal and onion architectures. Its single governing principle is the dependency rule: source code dependencies point only inward.

How it works

Each ring has a clear responsibility. Entities hold rules that would hold across the enterprise. Use cases orchestrate entities to fulfil a single application goal. Adapters convert data between use case format and the format of the web, database, or external systems. The outermost ring holds frameworks and glue.

Frameworks / Drivers
  Interface Adapters (controllers, presenters, gateways)
    Use Cases (interactors)
      Entities

A use case declares an output boundary interface; the presenter in an outer ring implements it. This is dependency inversion, which lets control flow go outward while source dependencies go inward.

interface UserGateway { byId(id: string): Promise<User> }
class ChangeEmail {
  constructor(private users: UserGateway) {}
  async run(id: string, email: string) { /* domain logic */ }
}

Pitfalls

  • Passing ORM entities or framework request objects across boundaries.
  • Creating a use case class per trivial read, producing pass-through code.
  • Treating the four rings as mandatory; the number of rings is flexible, the dependency rule is not.
  • Letting the database schema drive entity design.
  • Skipping enforcement; without lint rules or architecture tests, boundaries erode quickly.

Key takeaways

  • One rule matters: dependencies point inward.
  • Use cases are the unit of application behavior.
  • Frameworks are details to be kept at the edge.
  • Apply it where business rules justify the ceremony.

✓ When to Use

  • •Complex domains with long expected lifespan
  • •Systems that must support several delivery mechanisms
  • •Organizations standardizing structure across many services

✗ When Not to Use

  • •Small CRUD services
  • •Throwaway prototypes
  • •Teams where mapping boilerplate would dominate the work

Pros

  • +Business rules independent of frameworks
  • +Highly testable use cases
  • +Consistent structure across codebases

Cons

  • −Many small classes and DTO mappings
  • −Steeper learning curve
  • −Can be applied dogmatically where it adds no value

Cost Profile

Infrastructure

None — code structure only

Operational

Low — no runtime cost

Cognitive

Medium to high — many layers and rules

Failure Modes

  • Layer skipping, where controllers call repositories directly

  • Anemic entities, leaving rules scattered in use cases

  • Mapping explosion that slows every change

Real-World Examples

Alternatives

    Related Patterns

      Competency Domains

      requirements constraintseconomics evolution