Repositories hide how data is stored so services express business rules without knowing TypeORM, Prisma, or Mongoose details. This lesson shows a practical NestJS repository setup.
Why Use Repositories?
A repository is an injectable provider that exposes domain-friendly methods (findByEmail, save, deleteById) while encapsulating vendor-specific query APIs. Services depend on the repository interface, which makes unit tests and ORM swaps much simpler.
Register the abstract class as the token and the concrete class as useClass.
Keep repository methods named after domain intent, not ORM verbs alone.
Return domain entities/DTOs from repositories, not framework response objects.
Put cross-entity transaction orchestration in an application service, not every repository.
Repository Pattern Cheatsheet
Roles of each layer when using repositories.
Layer
Responsibility
Controller
HTTP mapping only
Service
Business rules and orchestration
Repository
Persistence reads/writes
ORM client
Low-level query execution
Testing With Fake Repositories
Because services depend on an abstract repository, unit tests can inject a Map-based fake without spinning up a database. That keeps service tests fast and focused on rules.
When a Thin Pass-Through Is Enough
For tiny CRUD apps, injecting Prisma/TypeORM directly into services can be acceptable. Introduce an explicit repository when you have repeated query shapes, multiple data sources, or heavy testing needs.
Common Mistakes
Creating a repository that merely renames every ORM method without adding value.
Leaking TypeORM QueryBuilder objects back to controllers.
Putting authorization decisions inside repositories instead of services/guards.
One giant "god repository" for every table in the application.