5 minute read

Layered Architecture

Why the oldest architecture pattern still builds the strongest foundations.

“Good architecture doesn’t hide complexity — it organizes it.” — A pragmatic software architect, probably sketching boxes and arrows on a napkin.


🖼️ Diagram

Layered Architecture Diagram

Diagram Caption: Five horizontal layers stacked top-to-bottom, with a dark vertical Cross-Cutting Concerns wedge (▶) slicing through them — showing utilities like logging, validation, and config that touch every layer but depend on none.


🧭 The Enduring Idea

If you’ve ever built an application — microservice, monolith, or hobby script — you’ve probably already used Layered Architecture. It’s the grandparent of nearly every pattern that followed: Clean, Hexagonal, Onion, and even the emerging Layered Ports Architecture (LPA).

Despite its age, the model keeps showing up because it delivers exactly what teams need most at the start of any project:

clarity, organization, and an easy mental map.


🪜What Layered Architecture Really Is

Layered Architecture is the canonical expression of separation of concerns. Each layer has a focused responsibility, and code may depend only on the layer directly beneath it. That one simple rule creates a predictable hierarchy that’s easy to teach and even easier to debug.

Let’s unpack the standard five-layer structure.

🟨 1. Presentation (API)

Where requests enter and responses leave. Typical contents:

  • Controllers, REST or gRPC endpoints
  • DTOs and mappers
  • Authentication or request filters

It translates external input into internal actions — and back again.

🟩 2. Service (Application)

The conductor of your orchestra. It coordinates use cases and workflows, deciding what should happen but not how persistence or UI work.

Define interfaces such as UserRepository or EmailGateway here — abstractions that the lower layers will implement.

🟥 3. Shared / Common

A neutral zone for reusable contracts, DTOs, and constants used across layers. It prevents duplication while keeping dependencies clean.

🟦 4. Domain

Your system’s beating heart — business logic, entities, and invariants. No HTTP imports, no SQL clients, no frameworks. If everything else vanished, the Domain would still define what the business means.

🟪 5. Infrastructure / Adapters

Reality meets code: databases, queues, APIs, filesystems. This layer implements the contracts defined above — persistence, gateways, integrations. It’s where technology decisions live.

▶ Cross-Cutting Concerns

Logging, configuration, crypto, validation — the things every layer needs but none should depend on. Our updated diagram shows them as a vertical wedge (▶) slicing through all layers, making their ubiquity explicit instead of an afterthought.


🧭 Why It Still Works (Even in 2025)

Technologies change. Business rules don’t. Layered Architecture protects those rules while letting teams build at the speed of understanding.

✅ Simplicity

Everyone gets it: Controller → Service → Repository. No PhD in design patterns required.

✅ Maintainability

Each layer changes in isolation. Refactor the database? No impact on the controller.

✅ Testability

You can mock lower layers and unit-test upper ones freely. The one-way dependency chain makes isolation trivial.

✅ Team Scalability

Front-end, back-end, and database teams can all work in parallel on their respective layers.

✅ Framework Freedom

Whether you’re using Quarkus, Spring, FastAPI, or Flask — the architectural flow remains the same.


⚖️ The Trade-offs

No pattern is perfect — and this one’s age shows in a few spots.

❌ Leaky Boundaries

It’s easy to cheat: a controller calls the repository “just this once,” and suddenly the separation collapses.

❌ Boilerplate

DTOs, mappers, and transformers everywhere. For tiny projects, that overhead can feel like ceremony.

❌ Over-Abstraction

Creating interfaces for everything leads to architecture astronaut syndrome. Use interfaces where change is likely, not everywhere.

❌ Limited Adaptability

Layered designs handle vertical flow beautifully, but struggle when multiple entry points or asynchronous channels appear — the very gap newer patterns like Hexagonal and LPA aim to fill.


💼 A Quick Example

A typical microservice request travels like this:

HTTP Request
   ↓
Controller (Presentation)
   ↓
Service (Application)
   ↓
Repository (Infrastructure)
   ↓
Database

Each step adds context, not confusion:

  • The controller validates input.
  • The service enforces business rules.
  • The repository persists data.

Swap out PostgreSQL for MongoDB? Only the repository changes. Add caching? Still localized. That’s the quiet power of good layering.


🧭 When (and When Not) to Use It

Reach for Layered Architecture when …

  • You need to get a project running quickly.
  • Your team values clarity and teachability.
  • Your domain logic is straightforward.

Think twice when …

  • You’re integrating multiple protocols or async flows → consider Hexagonal Architecture.
  • Your domain is deep and rule-heavy → consider Clean Architecture.
  • You want explicit, enforceable boundaries between every layer → see the upcoming Layered Ports Architecture (LPA).

🧮 Layered vs Clean vs Hexagonal

Feature Layered Clean Hexagonal
Learning Curve ⭐ Easy ⚙️ Medium ⚙️ Medium
Testability ✅ Good ✅ Excellent ✅ Excellent
Flexibility ⚙️ Moderate ⭐ High ⭐ High
Cognitive Load ⭐ Low ⚙️ Medium ⚙️ Medium
Best Use Case Web apps & APIs Complex domains Multi-protocol systems

Layered is the Swiss-Army knife: not the fanciest tool, but the one you actually use every day.


▶ Cross-Cutting Concerns Revisited

Our visual wedge deserves a little spotlight. Traditional diagrams leave “utilities” floating around with no home. By cutting a vertical slice (▶) through all layers, we acknowledge that:

  1. They’re universally available.
  2. They create no upward dependency.
  3. They’re best kept stateless and framework-agnostic.

Think Logger, Config, Validator, CryptoUtil, ExceptionMapper. Keep them lean, testable, and dependency-free — and your whole stack stays cleaner.


🧭 Toward Something Better: Layered Ports Architecture (LPA)

The next evolution — the Layered Ports Architecture — keeps the familiar stack but strengthens its boundaries.

Where classic Layered lets layers call the one below directly, LPA introduces a formal port at every boundary. Each adjacent pair talks only through a contract (a port), implemented by an adapter in the layer beneath. The result: tighter decoupling, better testability, and teams that can develop layers in parallel without stepping on each other.

You’ll find a full write-up in the companion article “LPA v5 — The Port Generalization Rule.”


🗯 Final Thoughts

Layered Architecture isn’t glamorous — and that’s its charm. It’s the design you can sketch on a napkin, teach to a junior dev, and still rely on in production a decade later.

Keep your layers clean, your utilities stateless, and your dependencies flowing downward. If you do, you’ll have built more than an app — you’ll have built a foundation.

“Simplicity is the soul of efficiency.” — Austin Freeman


🔗 References & Further Reading


Written for the Architectures Project, 2025.