Multi-tenant application architecture with Node.js - Express, and Mongoose
Recently, I have been working with node.js applications for which I had to create a multi-tenant environment. Let me share my findings with you all.
Multi-tenancy is an architecture where a single instance of an application serves multiple customers or tenants. A tenant is a group of users who share common access with a set of specific privileges to the application instance. With the help of multi-tenant architecture, we can provide each tenant with a shared instance of the infrastructure which includes computation time, database, access management, etc. As different tenants will be using the same instance of a service, the data schemas will have to follow a generic pattern.
So, the first question that arises is that, how do we segregate the incoming requests as per the tenants? If we find a way of separating the requests, we will be able to create a database connection for that tenant and use it for all the subsequent requests. This will ensure that data is stored on that tenant's database only and service context can be restored for that specific tenant also.
We will use Express which is a node.js application framework that will provide a boilerplate for our demo application. MongoDB as the database. For this, I am assuming that you have a working MongoDB server (local/cloud).
1.
Create these two databases. In this example the tenants main database is eb392598-c595-44a0-961e-8c143503a37d and tenant config database is Tenants.
2.
After creating the databases above add this document to the tenants' collection. Here, passwordSecret means the key that will be used while encrypting the password during registration. origin is the host address of your WebClient.
These are the properties that I have chosen for my JWT token payload. You can see tenentId property exists in the payload. We'll see how have we utilized that later on.
3.
For exchanging a set of information we have to prepare some schemas e.g. tenantSchema, userSchema. Create a new file tenant.js and add this code.
Create a new file user.js and write this code block. Our database schemas are ready. Now, we have to create a database connection and exchange data in-between them. As we may have multiple tenants, we have to create a tenant database connection pool to save and reuse the connections later. If we don't use a pool, each time the connection has to be remade which will slow down the throughput of our application. So, let's make a connection pool.
4.
Create another file dbContext.js and add these codes. Note, if the signature of the token is valid you will extract the tenantId from the token and embed that onto the req object.
JWT token holds all the necessary information that we will be needing for authorization. Let's decode the JWT token and extract the payload from the token. The payload contains a field tenantId.
Now, the key part is complete. We have successfully distinguished which tenant the request came from. Now, we just have to create the appropriate connection for that tenant and save that connection in the pool for future reference.
Finally, you have to add all these middlewares to enable multi-tenancy in your application. The sequence of the middleware matters. Sequence: verifyToken, dbContextAccessor, verifyUser.
5.
Here is an example of how to use the middlewares in your API. Here Users.find({}) will get all the users from request tenant only.
That's it... We're done !!! 😀
N.B: This is my first article. Let me know if this helps and share your thoughts if you have any. Thank you for reading.
The entire codebase is now open sourced. https://www.ittahad.xyz/open-sourced
i used similar but had to work on sharing multiple resources also great example
Hey good article! Do you have any github with the code? Thanks
Software Engineer-III @Money Forward, Inc.
5yGreat work. one suggestion, Please use typescript it will help you in future 🙂
Good one. Recently we are working to implement an identity server which works similar to support multiple tenants.