November 23, 2025 (1mo ago) — last updated January 1, 2026 (18d ago)

Clean Architecture by Robert C. Martin — TypeScript Guide

Distilled Clean Architecture principles from Robert C. Martin with practical TypeScript examples to build maintainable, testable, and scalable software.

← Back to blog
Cover Image for Clean Architecture by Robert C. Martin — TypeScript Guide

Clean Architecture separates your core business rules from frameworks, databases, and UIs, organizing code into concentric layers so dependencies always point inward. This guide distills Robert C. Martin’s approach and shows practical TypeScript patterns you can apply today to build testable, maintainable, and scalable systems.1

Robert C. Martin: Clean Architecture in TypeScript

Clean Architecture separates your core business rules from frameworks, databases, and the UI, organizing code into concentric layers so dependencies always point inward. This guide distills Robert C. Martin’s approach into practical principles and a TypeScript implementation blueprint you can use immediately.1

Architectural sketch showing concentric circles within a house structure representing clean architecture layers and dependencies

Introduction

Clean Architecture is a design approach that keeps your core business logic independent from frameworks, databases, and UIs. It organizes code into concentric layers with one simple rule: dependencies must point inward. That separation makes systems easier to test, maintain, and adapt as technologies and teams change. This guide distills Robert C. Martin’s ideas into clear principles and a TypeScript blueprint you can apply right away.1

What Is Clean Architecture?

Think of building a house where you can replace the foundation or rewire electrical systems without tearing down the walls. That’s the idea behind Clean Architecture: separate concerns so the most important parts—the business rules—remain pure and stable when external details change.

This layered model helps you focus on the application’s purpose first and implementation details second. That mindset is the first step toward software that’s durable and easy to evolve.

The Foundational Dependency Rule

At the heart of Clean Architecture is the Dependency Rule: source code dependencies can only point inward. Inner layers must not depend on outer layers. This creates a protective boundary around your business rules so they don’t become coupled to a specific database, framework, or UI.

By decoupling your software from technical details, you reduce the cost of change and future-proof your core logic. Developers can swap out tools without touching the rules that matter most, which helps teams deliver faster and with fewer regressions2.

Beyond a Simple Layered Model

Clean Architecture is not just another pattern. It’s a practical way to structure software for long-term projects. Teams that adopt modern architecture and delivery practices often see measurable improvements in lead time and stability2.

Clean Architecture vs Monolithic Architecture

AspectClean ArchitectureMonolithic Architecture
DependenciesControlled; point inward toward business logicTightly coupled components with direct dependencies
TestabilityHigh; core logic tested in isolationLow; tests often require full integration environments
MaintainabilityEasier; changes rarely affect core logicHarder; small changes can cascade
Technology ChoicesFlexible; external tools behave like pluginsRigid; switching tech is costly
FocusBusiness domain and rulesOften database or UI driven

The Four Layers of Clean Architecture

Robert C. Martin’s model uses four concentric layers. The innermost layer contains the domain core, shielded from external details. All dependencies point inward.

Concentric circles diagram illustrating clean architecture layers from core entities to outer frameworks and adapters

Layer 1: Entities

Entities are the pure business objects. They encapsulate fundamental business rules and data structures. For example, an Order entity might implement addItem() to check inventory and recalculate totals. Entities don’t know how they’re stored or presented.

Layer 2: Use Cases

Use Cases (or Interactors) implement application-specific business rules. They orchestrate Entities and repositories to achieve application goals, like PlaceOrder. Use Cases express intent and remain independent of UI and database implementations.

Layer 3: Interface Adapters

Interface Adapters translate data between the inner layers and external systems. Typical components include:

  • Presenters and Views: format data for display
  • Controllers: accept input from the UI and call Use Cases
  • Gateways/Repositories: abstract persistence with interfaces the Use Cases depend on

Adapters decouple core logic from frameworks by converting framework-specific types into plain data objects.

Layer 4: Frameworks and Drivers

The outer layer contains frameworks, databases, UI libraries, and other external tools. These are implementation details that should never be referenced by the inner layers. Because they sit on the outside, they can be swapped with minimal impact on the core.

Why Clean Architecture Matters

Adopting Clean Architecture is a strategic move that reduces long-term risk and cost. It improves testability, maintainability, and the ability to adopt new technologies without invasive rewrites. Teams that embrace well-structured architecture and modern delivery practices often see measurable gains in deployment speed and software reliability2.

Testability and Maintainability

When your core business logic is independent of external frameworks, you can write fast, reliable unit tests that don’t require databases or full UI stacks. Better testability leads to better maintainability, higher automated test coverage, and faster fixes.

Future-Proofing

Clean Architecture treats frameworks and services as replaceable plugins. If a database becomes too costly or a front-end framework falls out of favor, you can swap the outer layers and keep the inner rules intact. This flexibility makes it easier to integrate new capabilities, such as AI models, without wholesale rewrites.

A TypeScript Implementation Blueprint

Theory is useful, but code shows how principles map to practice. Here’s a practical folder layout for a TypeScript + Next.js application that enforces the Dependency Rule by design.

Hand-drawn diagram showing clean architecture layers with entities, use cases, and framework components connected by arrows

Make directories mirror layers so dependencies are obvious from the folder tree. This structure helps new developers get productive fast.

Core Domain Layer

  • src/domain/entities — business objects like Order.ts with methods such as addItem()
  • src/domain/repositories — interfaces like IOrderRepository.ts with findById(id: string) and save(order: Order)
  • src/domain/use-cases — orchestrators like CreateOrder.ts

This layer is framework-agnostic and fully testable in isolation.

Infrastructure Layer

  • src/infrastructure/repositories — concrete implementations, for example PrismaOrderRepository.ts
  • src/infrastructure/services — integrations like StripePaymentGateway.ts or SendGridEmailService.ts

Swap implementations without touching the domain by adhering to repository interfaces.

Presentation Layer

In Next.js, this maps to the app directory:

  • src/app/api/orders/route.ts — Controller that calls Use Cases and uses a Presenter for responses
  • src/app/orders/[id]/page.tsx — View component that renders UI and delegates complex logic to hooks

Keeping components thin and delegating logic improves readability and testability.

Sample Folder Structure (Next.js)

DirectoryResponsibilityExample Files
src/appPresentation Layer: UI and API routespage.tsx, layout.tsx, api/orders/route.ts
src/domainCore business logicentities/User.ts, use-cases/CreateUser.ts
src/domain/entitiesBusiness objectsOrder.ts, Product.ts
src/domain/repositoriesAbstract data contractsIOrderRepository.ts, IUserRepository.ts
src/domain/use-casesApplication rulesCreateOrder.ts, GetUserProfile.ts
src/infrastructureImplementations and servicesrepositories/PrismaOrderRepository.ts, services/Stripe.ts
src/libUtilities and typesutils.ts, constants.ts

This is a flexible starting point you can adapt as the project grows.

Common Anti-Patterns and Pitfalls

Using Clean Architecture poorly can create needless complexity. Here are common mistakes to avoid.

Anemic Domain Model

An anemic domain model turns Entities into mere data bags while moving business logic into bloated service classes. A healthy domain keeps logic inside Entities so they enforce their own rules.

Leaky Abstractions

If core logic imports framework types or database drivers, boundaries are leaking. Avoid passing framework-specific objects like NextApiRequest into Use Cases. Use Adapters to convert external inputs into plain data objects.

Dogmatic Over-Engineering

Apply Clean Architecture pragmatically. For small or short-lived projects, a lighter approach can be more efficient. Start with a clean separation between business logic and framework code, then introduce more formal layers as complexity increases.

Refactoring a Legacy App

You can migrate a legacy app gradually. Avoid big-bang rewrites. Use the Strangler Fig Pattern: replace one feature at a time with a clean implementation and reroute traffic once it’s ready. Repeat until the legacy code is replaced.3


At Clean Code Guy, we help teams audit and refactor codebases, run workshops, and deliver practical guidance so projects stay maintainable. Find out how we can help at https://cleancodeguy.com.

Frequently Asked Questions

Q: Is Clean Architecture overkill for small projects?

A: For quick prototypes, strict layering can add overhead. If a project may grow or be maintained long term, a clear separation between business logic and framework code offers big future savings.

Q: How does Clean Architecture differ from Hexagonal or Onion Architecture?

A: They’re variations on the same idea. All aim to protect core business logic by making dependencies point inward. Differences are mainly terminology and mental models.

Q: Can I migrate a legacy system to Clean Architecture without a full rewrite?

A: Yes. Use the Strangler Fig Pattern to incrementally replace components. Build new features with clean boundaries and gradually redirect traffic from the old system to the new one.3

Quick Q&A

What problem does Clean Architecture solve?

It protects core business rules from technical changes by enforcing inward-pointing dependencies so business logic stays stable and testable.

How do I start applying it in TypeScript?

Separate domain entities and use cases into src/domain, implement adapter interfaces in src/infrastructure, and keep UI and API code in src/app or src/presentation.

How should I approach a migration?

Incrementally: replace one feature at a time using the Strangler Fig Pattern until the legacy code is phased out.3

1.
Robert C. Martin, Clean Architecture: A Craftsman’s Guide to Software Structure and Design (Prentice Hall, 2017). [https://www.oreilly.com/library/view/clean-architecture/9780134494272]
2.
Google Cloud, Accelerate State of DevOps Report (2023). [https://cloud.google.com/devops/state-of-devops]
3.
Martin Fowler, “Strangler Fig Application.” [https://martinfowler.com/bliki/StranglerApplication.html]
← Back to blog
🙋🏻‍♂️

AI writes code.
You make it last.

In the age of AI acceleration, clean code isn’t just good practice — it’s the difference between systems that scale and codebases that collapse under their own weight.