Multitenant Node.js Application with mongoose (MongoDB)

Prakhar Jain
TechBlog
Published in
4 min readApr 27, 2020

Multitenancy is a reference to the mode of operation of software where multiple independent instances of one or multiple applications operate in a shared environment. The instances (tenants) are logically isolated, but physically integrated.

The term “software multi-tenancy” refers to a software architecture in which a single instance of software runs on a server and serves multiple tenants.

Architecting a multi-tenant system is more complicated than architecting a multi-user system. There are two models of architecting a multi-tenant system: Instance replication and Data-Segregation.

In the instance replication model, the system spins a new instance for every tenant. This is easier to start, but hard to scale. It becomes a nightmare when 100s of tenants signup.

In the data-segregation model, the application is shared between tenants but data of each tenant is stored in separate data stores. Separate data stores could be separate databases or separate schema within the same database.

Data Segregation is of two types

  • One DB with different schemas for a different tenant.
  • One DB per tenant.

separate schema ie. different tables within one DB for each tenant.

In this blog, we will discuss multitenancy with Data-Segregation Model with a single DB per tenant.

Create a Node app initialize one MongoDB connection along with the app and export this connection object. create this connection using mongoose createConnection as the createConnection method does not create default connection but return a DB connection object.

Here we are creating a MongoDB connection with mongoose and exporting it from here and it will be imported in config index.js file which will be initialized only once in the app and we can import this MongoDB object anywhere or we can also create and store it in global and can use it anywhere.

importing this MongoDB object and we can create a new MongoDB connection as per our tenant.

Mongoose provides useDb function which is used to create a new connection object it takes two params first one is DB name and another is options

Connection.prototype.useDb()Parameters:
name «String» The database name
{options} «Object» Configs
options = {useCache: false} «Boolean» False by defaultIf set true, cache results so calling useDb() multiple times with the same name only creates 1 connection object.Returns:
«Connection» New Connection Object

we are it switches to a different database using the same connection pool and Returns a new connection object, with the new DB, and using option {useCache: true} will create a single connection object for the same tenant if called multiple times.

To get the model from tenant DB, we need to create a schema of our model and pass it along with the tenant to this function, which will return a model. Now we can use this model to perform all of our crud operations.

In the Data access layer, we will first get the model as per our tenant DB connection and then perform crud operations. In each request, we have to pass tenantId and this tenantId will be used to switch with that tenant DB.

In this approach, we are using the same connection pool which we created at the time of app initialization. Multiple requests with different tenants will create different connection objects which will be timed out after 30 seconds if there is not new request with the same tenant.

There is another approach as well we can implement this will be helpful with limited no of tenants. In this, we can create a global object where the key will be tenantId/tenantName, and value will be the connection object. before every request we will check if the connection is there in this global object otherwise we will create a connection and store it there so in next request from that tenant will be reused.

In this above implementation, there can be a CPU usage issue if the number of the tenants will increase as the app will always have lots of open connection will degrade performance but it can be used in case you have fewer tenants and which will never grow dynamically.

--

--