Sitemap
DevBehindYou

DevBehindYou

I help businesses grow with Web Development, Data-Driven Insights, and SEO. Practical design, reliable performance, and outcomes that matter.

Clean Architecture: 5 Layers Every Developer Should Understand in 2026

12 min readSep 21, 2026

--

Key Takeaway: Clean Architecture organizes code into concentric layers where the important business rules sit in the center and never depend on the database, the UI, or any framework. One rule holds it together: source code dependencies only point inward. Get that rule right and your app stays testable and easy to change for years.

Press enter or click to view image in full size
Clean Architecture, Clean Architecture layers, Clean Architecture principles, dependency rule, separation of concerns, domain layer, application layer, presentation layer, infrastructure layer, entities, use cases, dependency inversion, software architecture

Think of a well-run company. The core mission, what the business actually does, does not change just because you switched from paper forms to a new software tool. The mission is protected in the middle, and the tools are on the outside, swappable at any time. Bad codebases do the opposite: the business rules get tangled into the database and the web framework, so changing a button means risking the payroll logic. Clean Architecture flips that. It puts your business rules in a protected core and pushes the database, UI, and frameworks to the edges where they belong.

The pattern comes from Robert C. Martin, known as Uncle Bob, who drew it as a set of rings (Uncle Bob). It shares its DNA with Hexagonal Architecture from Alistair Cockburn (Cockburn) and Jeffrey Palermo’s Onion Architecture. This guide explains the five layers in plain language, the single rule that makes it work, and real code so you can see it, not just nod at a diagram.

What is Clean Architecture?

Clean Architecture is a way of structuring software so that business logic is independent of frameworks, user interface, and databases. The goal, in Uncle Bob’s words, is “the separation of concerns,” achieved “by dividing the software into layers” (Uncle Bob). Each layer has one responsibility, and the inner layers never know the outer ones exist.

That independence buys four concrete things. Your code is testable, because you can test business rules with no database or UI attached. It is framework-independent, so a framework becomes a detail you can replace, not a cage you live in. It is UI-independent, so you can swap a web front end for a mobile app without touching the core.

And it is database-independent, so switching from one database to another is a change at the edge, not surgery on the heart. If you have ever been unable to upgrade a library because it was wired into everything, you already know the pain Clean Architecture prevents.

The mental shift that unlocks all of this is a single reframing: the database is a detail. So is the web framework, and so is the UI. Beginners treat the database as the center of the app and build everything around it. Clean Architecture treats it as a plug-in at the edge, no more central than the printer.

The center is your business rules, the thing that makes your product worth money, and everything else is a replaceable device serving that center. This is the same idea Cockburn captured with ports and adapters and that appears across the whole family of layered patterns (Hexagonal architecture)).

Press enter or click to view image in full size
The Clean Architecture concentric circles: Entities at the center, then Use Cases, then Interface Adapters, then Frameworks and Drivers, with a single arrow showing dependencies pointing inward

The Dependency Rule: the one rule that matters

If you remember nothing else, remember this. Uncle Bob calls it the Dependency Rule, and it is the whole game: “Source code dependencies can only point inwards. Nothing in an inner circle can know anything at all about something in an outer circle” (Uncle Bob).

In plain terms: the center can never import from the edges. Your business rules must not mention your database library, your web framework, or your UI toolkit. Those are all outer-ring details. This feels backwards at first, because the use case obviously needs to save data to a database.

The trick that resolves it is dependency inversion: the inner layer defines an interface, and the outer layer implements it. The use case says “I need something that can save an order,” and the database adapter provides it, without the use case ever knowing it is talking to Postgres.

// INNER layer (use case) defines what it needs, as an interface.
interface OrderRepository {
save(order: Order): Promise<void>;
}

// The use case depends on the interface, never on a database.
class PlaceOrder {
constructor(private orders: OrderRepository) {}
async run(order: Order) {
order.validate(); // business rule lives in the entity
await this.orders.save(order); // talks to an abstraction, not Postgres
}
}

// OUTER layer (infrastructure) implements the interface.
class PostgresOrderRepository implements OrderRepository {
async save(order: Order) { /* real SQL here */ }

Notice the direction. PlaceOrder knows about OrderRepository, but OrderRepository knows nothing about Postgres. The database points inward at the interface, not the other way around. That single inversion is what keeps the core clean.

Press enter or click to view image in full size
Dependency inversion: the use case depends on an interface it owns, and the database adapter implements that interface, so the source dependency points inward even though control flows outward

The 5 layers of Clean Architecture explained

Uncle Bob draws four rings, but in practice most teams describe five layers, splitting the outer ring into infrastructure and the framework glue that sits at the very edge. The terminology varies, so focus on the responsibility, not the label. Here are the five, from the protected center outward.

Layer 1: Entities (the core business rules)

Entities are the heart: the objects and rules that would be true even if your software did not exist. An Order knowing it needs at least one item is a business rule, not an app feature. These have zero dependencies on anything technical. They are pure logic, and they change least often.

// Layer 1: pure business rules, no frameworks, no database.
class Order {
constructor(public items: Item[]) {}
validate() {
if (this.items.length === 0) throw new Error("Order needs at least one item");
}
}

Layer 2: Use Cases (application logic)

Use cases orchestrate the entities to perform a specific action the app offers, like “place an order” or “cancel a subscription.” They contain the application-specific rules and coordinate the flow, but they still know nothing about the web or the database. The PlaceOrder class above lives here.

A useful way to think about the split: entities are rules that are true for the whole business, while use cases are rules that are true only for this application. “An order needs at least one item” is an entity rule. “Placing an order sends a confirmation email and reserves stock” is a use case, because it describes what your app does with that order. Keep the two separate and each stays small and clear.

Layer 3: Interface Adapters

This layer translates between the inner world and the outer world. Controllers take an HTTP request and call a use case. Presenters take a use case result and format it for the screen. Gateways adapt the repository interface to a specific database. Nothing here contains business rules. It only converts shapes, from JSON to objects and back.

A good test for this layer: every class in it should be deletable and rewritable without changing a single business rule. If deleting a controller forces you to change a use case, the two are tangled and the boundary has slipped.

Layer 4: Infrastructure

Infrastructure holds the concrete implementations of the interfaces your inner layers defined: the actual Postgres repository, the real email sender, the file storage client. This is where third-party libraries live. When you switch databases, this is the layer you rewrite, and the core does not notice.

Layer 5: Frameworks and Drivers

The outermost layer is the glue: the web framework, the UI toolkit, the main function that wires everything together at startup. Uncle Bob says you keep this layer thin, because it is the most likely to change. Frameworks are tools you use, not foundations you build on. This is also where dependency injection happens: at startup, the outer layer creates the concrete Postgres repository and hands it to the use case that only knows the interface.

That wiring is the one place in the whole app that is allowed to know every layer, and keeping it small and boring is a feature. When a junior developer asks “where do I plug in the real database,” the answer is always here, at the edge, never in the core.

Press enter or click to view image in full size
The 5 layers as nested boxes from Entities (center) to Frameworks and Drivers (edge), each labeled with what belongs in it and an example

How the layers work together: a request walkthrough

The layers feel abstract until you trace one request through them, so let us follow “place an order” from the outside in and back out. This is the flow every Clean Architecture app repeats thousands of times a day.

A request arrives at the web framework, layer 5, which hands it to a controller in layer 3. The controller parses the input and calls the PlaceOrder use case in layer 2. The use case tells the Order entity in layer 1 to validate itself, then calls its OrderRepository interface to save.

Get DevBehindYou’s stories in your inbox

Join Medium for free to get updates from this writer.

At runtime, that interface is really the Postgres adapter in layer 4, but the use case never learns that. The result travels back out: the use case returns a plain result, a presenter in layer 3 formats it, and the framework in layer 5 sends the HTTP response.

// Layer 3: the controller adapts HTTP to a use case call. No business logic here.
class OrderController {
constructor(private placeOrder: PlaceOrder) {}
async handle(req: Request, res: Response) {
const order = new Order(req.body.items); // shape the input
await this.placeOrder.run(order); // call inward
res.status(201).json({ status: "created" }); // shape the output
}
}

Two directions are at play, and separating them is the whole insight. Control flows outward, from the request into the framework and out to the database. But source code dependencies point inward, because every arrow of “who imports whom” leads toward the center. The database depends on the use case’s interface, never the reverse.

The fastest way to check if you got Clean Architecture right is to look at your entity and use case files and search their imports. If they import anything from your web framework or database library, the dependency rule is broken. The core should read like plain business logic that could run anywhere.

Benefits, and when Clean Architecture is overkill

The benefits are real: independent testing, swappable databases and frameworks, and a codebase where a new feature touches predictable places. On a large, long-lived system with real business complexity, Clean Architecture pays for itself many times over, because change stays local instead of rippling everywhere.

The testability point alone is worth the price on a serious system: because the core has no database or network, its tests run in memory in milliseconds, so a team can run thousands of them on every commit. That fast feedback is what lets a codebase stay confident under constant change, and it is nearly impossible to get once business logic is welded to a live database.

But it is not free, and using it everywhere is a beginner mistake. All those interfaces and layers add indirection and files. For a simple CRUD app, a weekend script, or a tiny microservice that just forwards data, the ceremony costs more than it saves, and a straightforward two-layer structure ships faster.

Match the architecture to the stakes: reach for Clean Architecture when the business logic is complex, the app will live for years, or a team needs clear boundaries to work without stepping on each other. Skip it when the app is small, short-lived, or mostly plumbing.

You do not have to adopt all five layers on day one. Start by pulling your business rules out of the framework into plain classes with no imports from the outside. That one move captures most of the benefit. Add the full layering only where the complexity earns it.

Common mistakes with Clean Architecture

Clean Architecture fails in a few predictable ways, and every one of them comes from letting a detail leak into the core. Knowing the traps is half the battle.

The most common is letting framework types reach the center. The moment an entity imports a database annotation or a web request object, the dependency rule is broken and the core is no longer independent. Keep those types in the outer layers and map to plain objects at the boundary. A second mistake is anemic entities, where the business rules drain out of the entities into the use cases or, worse, the controllers, leaving entities as hollow data bags. The rules belong with the data they govern.

A third is over-abstracting: creating an interface for something with exactly one implementation that will never change, which adds indirection for no benefit. Invert dependencies at the real boundaries, database, network, UI, not everywhere. The fourth is skipping the mapping and passing database rows straight to the UI, which quietly couples your screen to your schema, so a column rename breaks the front end.

The cure for all four is the same: guard the boundary. At every line between an inner and an outer layer, convert to a plain object the inner layer owns, and let nothing framework-shaped cross inward.

Draw your dependency arrows on a whiteboard before you write code. If any arrow points outward, from an inner layer to an outer one, you have found a design bug before it became a code bug. The picture is cheaper to fix than the codebase.

How DevBehindYou Can Help You Structure a Codebase That Lasts

Press enter or click to view image in full size
devbehindyou

Codebases rot when architectural boundaries completely collapse. Business logic slowly leaks into UI controllers and database queries. DevBehindYou engineers maintainable, production-ready systems from day one. I keep the entire audit, architecture, and implementation loop in a single head, eliminating messy agency handoffs.

  • Architecture Audits: I inspect your exact codebase, identify boundary leaks, and map out clean layers.
  • Domain Modeling: I isolate your business rules into framework-independent entities and use cases.
  • Production Implementation: I configure proper dependency inversion, implement data mappers, and build fast in-memory test suites.

Ready to structure an application that scales cleanly? Book an architecture audit at DevBehindYou and ship a codebase built to last.

Final Thoughts

Clean Architecture is one idea wearing five layers: protect your business rules in the center and point every dependency inward, so frameworks, databases, and UIs become swappable details. Trace one request through the layers and the discipline clicks, keep the dependency rule and your app stays testable and calm under change.

Build the company where the mission sits safe in the middle and the tools stay on the outside. The reward is not architectural purity for its own sake, it is the freedom to change your database, your framework, or your entire front end years from now without touching the logic that makes your product valuable.

If you want a second look at where your boundaries are leaking before a codebase gets hard to change, DevBehindYou offers a free technical audit that maps a cleaner structure.

FAQs

1. What is Clean Architecture?

Clean Architecture is a way of structuring software into concentric layers so business rules stay independent of frameworks, UI, and databases. The core holds pure logic, outer layers hold technical details, and source dependencies only point inward, which keeps the code testable and easy to change.

2. What is the Dependency Rule in Clean Architecture?

The Dependency Rule states that source code dependencies can only point inward, and nothing in an inner circle can know anything about an outer circle. In practice, inner layers define interfaces and outer layers implement them, so the database depends on the core, not the other way around.

3. What are the 5 layers of Clean Architecture?

Entities hold core business rules, use cases hold application logic, interface adapters translate between inner and outer worlds, infrastructure holds concrete implementations like the database, and frameworks and drivers are the outermost glue. Uncle Bob draws four rings, and teams commonly split the outer ring into two.

4. Is Clean Architecture the same as Hexagonal or Onion Architecture?

They are close cousins with the same core idea: keep business logic independent and depend on abstractions. Hexagonal Architecture calls them ports and adapters, Onion Architecture uses layered rings, and Clean Architecture unifies the family. The naming differs, the dependency direction does not.

5. When should I not use Clean Architecture?

Skip it for small, short-lived, or simple apps where the extra interfaces and files cost more than they save. A basic CRUD tool or a tiny service that forwards data ships faster with a flat structure. Reach for Clean Architecture when business logic is complex and the app must last.

6. Does Clean Architecture work with any language or framework?

Yes. It is a structural idea, not a library, so it applies to Java, Kotlin, TypeScript, Python, Go, and more. The key mechanism, dependency inversion through interfaces, exists in every serious language, which is exactly why the pattern outlives any single framework.

DevBehindYou is Ashutosh Sharma. Developer by heart, SEO specialist by mind, analyst by habit. I build web and mobile products, then engineer them to be found. Same person, same project, no handoff in between.

--

--