Repository Pattern
The Repository pattern is an architectural pattern that mediates between the domain/business logic and data mapping layers, exposing a collection-like interface for accessing domain objects while hiding the underlying data source and…
Definition
The Repository pattern is an architectural pattern that mediates between the domain/business logic and data mapping layers, exposing a collection-like interface for accessing domain objects while hiding the underlying data source and persistence details.
Overview
The Repository pattern was popularized by Eric Evans's Domain-Driven Design and Martin Fowler's Patterns of Enterprise Application Architecture as a way to decouple business logic from the specifics of data access. A repository exposes an interface that looks like an in-memory collection of domain objects — methods like `findById`, `findAll`, `add`, `remove`, or query methods expressed in domain terms — while internally translating those calls into whatever the actual persistence mechanism requires: SQL queries via an ORM, HTTP calls to a remote API, document lookups in a NoSQL store, or even in-memory storage for tests. The core benefit is separation of concerns: application and domain logic depends only on the repository's abstract interface, not on any specific database technology, ORM, or query language, which means the persistence implementation can be swapped (e.g., migrating from one database to another, or from a real database to an in-memory fake for testing) without touching business logic. This aligns closely with the Dependency Inversion Principle and is a natural fit for hexagonal/ports-and-adapters architecture, where a repository interface is a 'port' defined by the domain layer, and a concrete repository implementation (backed by a specific database) is an 'adapter' plugged in at the application's boundary. Repository is one of the most widely adopted patterns in enterprise and web application backends, appearing across virtually every major language and framework ecosystem — Spring Data repositories in Java, Entity Framework's repository-adjacent patterns in .NET, and hand-rolled repository classes wrapping ORMs like Django's ORM, SQLAlchemy, or Prisma. A frequent point of debate is whether an ORM's query builder (like Django's or SQLAlchemy's) already functions as a repository, making a hand-written repository layer redundant, versus cases where an explicit repository still adds value by encapsulating complex queries, enforcing domain invariants on data access, and providing a seam for test doubles. Overuse of the pattern — wrapping simple CRUD with a repository that adds no real abstraction — is a commonly cited anti-pattern, since it can add boilerplate without meaningfully decoupling anything.
Key Concepts
- Exposes a collection-like interface (add, remove, findById, findAll) for domain objects
- Hides underlying persistence details (SQL, ORM, HTTP, NoSQL) behind an abstract interface
- Decouples business/domain logic from specific data-access technology
- Aligns with the Dependency Inversion Principle and hexagonal architecture's 'ports'
- Enables swapping real databases for in-memory fakes/mocks in unit tests
- Commonly implemented as a thin wrapper around an ORM or query builder
- Widely supported across frameworks (Spring Data, Entity Framework, custom wrappers)
- Can become boilerplate-heavy anti-pattern if it adds no real abstraction over simple CRUD