Implementing a Generic Repository Pattern Using NestJS
Generic Repository — A NestJS and Mongoose implementation
Repositories are classes or components that encapsulate the logic required to access data sources. They centralize common data access functionality, providing better maintainability and decoupling the infrastructure or technology used to access databases from the domain model layer. — Design the infrastructure persistence layer
Abstracting our data access layer will decouple our application business logic from implementation details such as mongo db/sql data access code.
Frameworks changes such as DB framework change shouldn’t affect our core services, they should be transparent to our business logic code.
Our Services should be dependent only on abstraction and not on implementation. The same goes for data services.
for example, we have a books store microservice. we have an “add new book” use case, in this use case we use the book repository in order to add new book. we don’t care about specific DB implementation and we don’t want to be bound to any DB.

You can find all the code with full examples in this repo
Our Entities for Author
, Genre
and Book
are:
Abstraction
First, let’s create our abstractions:
The code for AbstractRepository
class is given below:
- You can add as many functionalities as you need.
T
represent each entity
The code for AbstractDataServices
class is given below:
- We expose 3 repositories, one for each business entity.
- Each repository expose all the generic repository functions
So these are our abstractions, our business services can work with them without any implementation.
now it is time to add an implementation, in this article we will implement our data services with mongoose.
MongoDb Implementation
Our MongoDB implementation will be wrapped inside a module and we will expose only abstraction.

We need to implement:
- Mongo Model — with all mongo specifications
- Our generic repository — connected to mongo
- data services- expose our mongo repositories
Model
First, let’s create our entities, they will be decorated with mongoose decorators
Mongo Generic Repository
Let’s implement our mongo generic repository
- Simple mongo Implementation.
populateOnFind
will give us the ability to populate our model with connected entities
Mongo Data Services
Here we need to create our repositories and expose them to our consumers
Mongo Data Services Module
In this module, we will:
- Add the connection to the MongoDB
- Tell our DI engine to create
MongoDataServices
each time a class asks forIDataServices
Main Data Services Module
This module is not a must, but I like to create it because it hides any specific implementation from our main module
Plug The Module To Our Main Application
- Using our early created
DataServiceModule
we don’t see any mongo implementation stuff here, we are only adding theDataServiceModule
.
Let’s Take this beauty for a ride
Now let’s use our shiny new data services in our application.
For example, let's use it in our books service for fetching books and adding new books to our DB.
- We inject
IDataServices
to our service - Our use case logic doesn’t depend on any DB implementation, only on abstraction.
- Changing our DB provider doesn’t affect our use case code at all.
Let’s say we want to change our DB provider, all we need to do is:
- Create a new DB module, including :
GenericRepository
,DataServices
- Consume the new module in the
DataServicesModule
That’s it, no other change in our app. Your boss will be happy :)
Repository pattern is a great way to decouple your app from external DB frameworks, and generic repositories reduce the amount of code you need to write in order to accomplish it.
Next Steps
You can read more about implementing a clean architecture in your NestJs application in an article I wrote on the subject— Clean Node.js Architecture — With NestJs and TypeScript