Tiers of Software Architecture
Every application is a set of components — a UI, some logic, a database, maybe a cache or a queue. A tier is a decision about where each of those components physically lives. This chapter walks from the simplest arrangement (everything on one machine) to the sprawling distributed systems behind Instagram and Uber, and shows why each step up the ladder exists.
After this you should be able to
- Explain the core idea in Tiers of Software Architecture
- Apply Tiers of Software Architecture in a representative design
Every application is a set of components — a UI, some logic, a database, maybe a cache or a queue. A tier is a decision about where each of those components physically lives. This chapter walks from the simplest arrangement (everything on one machine) to the sprawling distributed systems behind Instagram and Uber, and shows why each step up the ladder exists.
Each tier type is its own section, but they build on each other as a story: every new tier is the fix for a limitation of the one before it. Anything marked [+] is context I've added beyond the source lesson — usually a definition, an example, or a "why." Diagrams are color-coded by component role: UI, app/logic server, database, cache/queue, NoSQL/async.
A tier is a decision about where a component runs#
Think of a tier as the physical and logical separation of the components that make up an application. The key word is components — not code. A tier boundary is not "this function versus that function"; it's "this whole component runs on a separate machine from that one."
The components a web service is built from include:
- User interface — what the user sees and interacts with.
- Backend application server — where the business logic runs.
- Database — where data is stored and persisted.
- Caching — fast temporary storage to avoid repeated work. [+]
- Messaging — moving work and events between parts of the system. [+]
The number in "single-tier," "two-tier," "three-tier," and "n-tier" simply counts how many separate machines those components are spread across. That's the whole idea. The sections below make it concrete.
Single-tier: everything on one machine#
UI, business logic, and database all live on the same machine. There is no network between them — the app talks to its data by reaching across memory and disk on the same computer. Classic examples are desktop software: MS Office, PC games, image editors like Photoshop or GIMP.
Upsides#
- No network latency. Every component is local, so data is instantly available. This is the single biggest performance advantage — two-, three-, and n-tier apps constantly send requests over a network, which adds delay a single-tier app never pays.
- Strong data privacy. The user's data never leaves their machine, so there's nothing to intercept in transit.
[+] The catch on performance: it's only as good as the user's hardware. A heavy app on a weak machine still feels slow, because there's no server to offload work to.
Downsides#
- No control after shipping. Once the software is on the customer's machine, the publisher can't push fixes or features. Updates only happen when the user manually downloads a patch or connects to a remote server.
- Bugs are permanent until patched. In the '90s, a game shipped with buggy code stayed buggy, and studios took the heat. This made pre-release testing make-or-break — there was no room for mistakes.
- Weak product security. The code sits on the user's machine, so it can be reverse-engineered, tweaked, or copied for profit. A server-side architecture, where the company controls the machine, can defend itself far better.
- Inconsistent experience. Look, feel, and performance vary with each user's hardware and configuration.
Two problems dominate: the publisher can't update or secure the software, because they don't own the machine it runs on. The obvious fix — move something you do control onto a machine you own. That's a two-tier app.
Two-tier: pull the database onto a server you own#
The client holds the UI and the business logic together; the database runs on a separate server the business controls. So there are two machines — client and database server — and one network hop between them.
Why keep logic on the client?#
A fair objection: the code still lives on the client, so it's still vulnerable to being read or copied — and it is. Two-tier is the right call when that exposure doesn't hurt the business much, and the tradeoff buys real advantages:
- Fewer network calls, lower latency. Because logic and UI sit together, most work happens locally. The app only reaches the server at meaningful moments.
- Cheaper to run. Fewer server calls means less server load, which means less money spent keeping servers up.
A to-do or planner app only hits the database when you finish a list and want to save it. Browser and mobile games download their heavy files once on first use, then contact the backend only to persist game state. In both, exposing the code causes little harm, and the latency win is worth it.
Whether to keep logic on the client or move it to its own server is a business-requirements call. Move the logic to a dedicated backend, and you've built a three-tier app.
Three-tier: give the logic its own machine too#
UI, business logic, and database each run on their own separate machine. All three are physically separated into distinct tiers. This is the workhorse of the web — nearly every simple site (blogs, news sites) is a three-tier app.
Concretely, a simple blog: the UI is HTML, JavaScript, and CSS; the logic runs on a server like Apache; the data lives in MySQL. Three machines, three responsibilities. This works best for straightforward use cases — and when the app grows past "straightforward," you start adding components beyond these three. That's n-tier.
N-tier: more than three components in play#
An n-tier application involves more than the three core components. Beyond UI, application server, and database, it pulls in specialized pieces, each on its own tier:
- Cache — fast lookups without hitting the database.
- Message queues — asynchronous behavior, so work can happen out of band.
- Load balancers — spread traffic across many servers.
- Search servers — search through massive amounts of data.
- Data-processing components — crunch huge volumes of data.
- Heterogeneous services — web services and microservices, often running different tech stacks.
Almost every large-scale product is n-tier: social apps like Instagram, Facebook, and TikTok; consumer services like Uber and Airbnb; massively multiplayer games like Pokémon Go and Roblox. N-tier applications are more commonly known as distributed systems.
Why break a system into so many tiers?#
Two design principles explain the whole progression. Both push in the same direction: give each component one job, and keep it loosely coupled to the rest.
Single responsibility principle#
Give a component one dedicated responsibility and let it do that flawlessly — persist data, or run application logic, or guarantee message delivery, but not several at once. The payoffs:
- Easier management. Dedicated teams and code repositories per component keep things clean.
- Isolated failure. Components are loosely coupled, so a change to one doesn't break another. Patch the database's OS and — even if the install goes wrong — only the database goes down. The rest of the app stays up; only features that need the database are affected.
Stored procedures put business logic inside the database — a violation of single responsibility. Swap in a different database later and the logic has nowhere clean to go: you either drag it to the new database or awkwardly refactor it into the app. A database should only persist data. Keeping logic out of it is exactly why logic gets its own tier.
Separation of concerns#
Loosely, the same idea: each part minds its own work and stops worrying about the rest. It applies at every level — across tiers and inside code. Keeping components separate makes them reusable: different services can share the same database or messaging server, as long as they aren't tightly coupled. Loose coupling is the goal, because it's what lets you scale the system when it grows past a certain size.
You add tiers to give each component one job and to keep them loosely coupled. That's what makes a system manageable, resilient, reusable, and — above all — scalable.
Layers are not tiers#
These get used interchangeably, but in the industry they mean different things. Tiers are physical; layers are logical.
- Tier — the physical separation of components across machines. (Everything above.)
- Layer — the conceptual, logical organization of code. Typical layers: user interface, business, service, and data-access.
Layers live at the code level, independent of how many machines are involved. The same set of layers can appear inside any tiered app — single, two, three, or n-tier.
| Tier | Layer | |
|---|---|---|
| Separates | Components across machines | Code by responsibility |
| Nature | Physical | Logical / conceptual |
| Example | Browser · Apache · MySQL | UI · business · service · data-access |
| Counting | Single, two, three, n-tier | Any number, inside any tier |
Recap#
Each rung up the tier ladder exists to fix a limitation of the one below — trading local speed for control, security, and the ability to scale. You climb only as far as your requirements demand: give every component one job, keep them loosely coupled, and add a tier only when a real constraint pushes you to.
Further reading [+]#
The source lesson lists no references, so these are added starting points I verified as live. Grouped by topic.
All three links were fetched and resolved live on August 13, 2026. No page showed material changes that would contradict the concepts above.