We use analytics cookies.We use cookies to analyze site traffic and improve your experience.
Loading...
System Design Masterclass · Microservices Architecture
Free preview: the first 2 parts of this 8-part lesson.
Already bought the course? Sign in to read the whole lesson.
this lesson is part of
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design courseread the rest of this lesson in
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design coursein Microservices Architecture
This lesson is part of the full System Design Masterclass. Unlock it along with 769 other lessons for a one-time payment.
One-time payment by card or PayPal
Get Lifetime AccessOne-time payment: UPI, card or netbanking
Get Lifetime Access18 Foundation lessons are free, no payment needed. Try them now
It is easy and good
“It is really nice and good Please join the course”
When you go to a library, you don't wander through the stacks searching randomly. You use the catalog system, search by title, author, or subject, and it tells you exactly where to find the book. You don't need to know whether the library organizes books by Dewey Decimal or Library of Congress. You don't need to know if some books are in the basement and others on the third floor. The catalog provides a clean interface: search, find, retrieve.
The Repository pattern does the same thing for data access. Your business logic says "give me all active users" and the repository figures out whether that means a query, a MongoDB aggregation, an API call, or a cache lookup. The business logic never knows and never cares.
Why does this matter? Because the moment your business logic contains SELECT * FROM users WHERE status = 'active', you can never switch databases without rewriting business logic. You can never unit test without a real database. You can never change your query optimization strategy without touching every service that reads users.
Martin Fowler's original description frames a repository as "an in-memory collection of domain objects." The service layer treats it like a list. Add things, remove things, query for things. What actually happens behind the interface could be a Postgres query, a DynamoDB scan, a Redis lookup, or an call to another service.
The Repository pattern mediates between the domain and data mapping layers, acting like an in-memory collection of domain objects.
| Responsibility | Repository | Direct DB Access |
|---|---|---|
| Where queries live | In the repository class | Scattered across business logic |
| Swapping databases | Change one repository implementation | Rewrite every file that queries data |
| Unit testing | Mock the repository interface | Need a real database or complex mocks |
| Query optimization | Centralized in one place | Spread across the codebase |
| Domain language | userRepo.findActiveUsers() | db.query("SELECT * FROM users WHERE...") |
A repository typically exposes methods like findById, findAll, save, delete, and domain-specific queries like findByEmail or listActiveWithSubscription. It looks like a collection. You add things, remove things, and query for things.
The key insight is that the repository interface lives in the domain layer, not the infrastructure layer. The domain defines what it needs ("give me active users"), and the infrastructure provides an implementation that fulfills that contract. This inversion of control is what makes the pattern powerful.