N-Tier Architecture
How a Chaotic Codebase Taught Me the Value of Separation
Early in my career, I built a small internal web tool for a team I worked with β a simple inventory tracker with a PHP backend, MySQL database, and HTML forms. Everything lived in single files. Database queries mixed with HTML markup mixed with business validation.
Adding a new field meant touching the query, the HTML, the validation logic, and the export function β all in the same file. A change in one place routinely broke something else. The system worked, but maintenance was painful beyond belief.
When I refactored it using N-Tier architecture, I divided the application into distinct tiers with clear responsibilities. The improvement in maintainability was immediate. That experience shaped how I thought about structure for years afterward.
Table of Contents
What Is N-Tier Architecture?
N-Tier (also called multi-tier) architecture divides a system into physically or logically separated tiers, each with a distinct responsibility. Tiers communicate only with adjacent tiers β Presentation talks to Business Logic, Business Logic talks to Data Access. Presentation never touches the database directly.
The "N" means the number of tiers is not fixed β common configurations are 2-tier, 3-tier, and 4-tier.
The Classic Three-Tier Model
This is the most common configuration and where I started:
Tier 1 β Presentation
Responsible for rendering output and accepting input. In a web application this is the HTTP layer β controllers, request parsing, response serialisation. It should contain no business logic.
Tier 2 β Business Logic (Application)
Contains the rules of the domain: validation, calculations, orchestration of operations. This tier does not know how data is stored β it only knows what data it needs.
Tier 3 β Data (Persistence)
Responsible for reading and writing data. Abstracts the underlying database behind repositories or data access objects. The business logic tier never writes raw SQL β it calls repositories.
The Four-Tier Model
In larger applications I often add a fourth tier β or split one of the existing tiers:
Presentation
HTTP request/response, routing, serialisation
Application
Use cases, orchestration, input validation
Domain
Business rules, domain models, invariants
Infrastructure
Database, external APIs, message queues
This maps closely to the Onion and Clean Architecture styles. See Onion Architecture for the code-level perspective.
N-Tier vs Layered Architecture
These are often used interchangeably but they refer to different things:
Concern
Deployment and process boundaries
Code organisation within a process
Scope
System topology
Codebase structure
"Tier" =
Separate process / server (can be on different machines)
Logical module within the same process
Example
Web server + App server + DB server
Controller β Service β Repository in same app
In practice, an N-Tier system usually also has layered code organisation within each tier.
Practical Example: Python Web Application
Here is how I structure a three-tier Python web application. This follows the same pattern I used before breaking my POS system into microservices.
The presentation tier knows HTTP semantics. The business logic tier knows domain rules. The data tier knows the database. None of them bleed into each other.
Deployment Topology
One of the real advantages of N-Tier is physical deployment separation. In production, my tiers have lived on different machines:
I can scale the application tier independently of the database tier. I can replace the database without touching the application servers. This is physical tier separation at work.
When to Use N-Tier
Web applications where presentation, logic, and data have naturally distinct concerns
Teams where different people own different tiers (frontend, backend, DBA)
Systems where tiers need to be independently deployed or hosted
Regulated environments where data access must be auditable and controlled
Limitations
Strict tiering can create unnecessary indirection. Not every read operation needs four layers of abstraction.
Cross-cutting concerns are awkward. Logging, caching, and error handling do not belong cleanly in one tier.
Changes often ripple through all tiers. Adding a new field to a model frequently requires changes at every layer.
Not suitable for complex domain logic. When domain rules are rich and interrelated, N-Tier becomes rigid. Onion or hexagonal architectures handle this better.
Lessons Learned
Follow the rule strictly at first, then bend it deliberately. Understanding why Presentation must not access data directly makes you better at choosing when to break the rule.
The data access tier is your friend. Being forced to write a repository method rather than inlining SQL everywhere saved me from countless query bugs.
Thin controllers, fat services. If my router functions are more than 10 lines, business logic has leaked into the presentation tier.
Naming matters. Calling your layers
controllers/,services/, andrepositories/signals the intent to every developer on the team.
Last updated