Introduction
Hi, in this post I will describe how to setup and use multiple database connections with a simple example.
NestJS Documentation is great for the most part but it has some important omissions on the multiple databases section.
I will proceed under the assumption that you already have created a NestJS application and have your 2 or more databases setup and ready to be connected to. Let's go straight to the point.
Let's get to it
Define DB connection options
Following NestJS docs we will find the connection options example credentials directly set on code.
...
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'test',
entities: [Customer],
synchronize: true,
}),
],
})
...
Instead of having credentials exposed on the code like that we should use an environment configuration file or a similar strategy.
For this example we will make use of the @nestjs/config
package to get the database credentials from an environment file. You can find more information about how to install and use the config package at NestJS Configuration Docs. It is a simple process.
...
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => {
return {
type: 'mssql',
host: configService.get('MAIN_DB_HOST'),
port: parseInt(configService.get('MAIN_DB_PORT')),
database: configService.get('MAIN_DB_DATABASE'),
username: configService.get('MAIN_DB_USERNAME'),
password: configService.get('MAIN_DB_PASSWORD'),
schema: configService.get('MAIN_DB_SCHEMA'),
entities: [Customer],
synchronize: false,
};
},
}),
...
We don't need to define a connection name four our first connection. It will be named 'default' by default 😬. For any other defined connections we will need to provide a name.
NestJS docs tells us that the name
property should be added inside the options object, at the same level as host, port, etc.
...
@Module({
imports: [
TypeOrmModule.forRoot({
...defaultOptions,
host: 'user_db_host',
entities: [User],
}),
TypeOrmModule.forRoot({
...defaultOptions,
name: 'albumsConnection',
host: 'album_db_host',
entities: [Album],
}),
],
})
...
Now, because we are getting our credentials from the .env
file and using forRootAsync
we need to add the connection name
property outside of the useFactory
function 👀. This is a really important detail that is not mentioned anywhere in the docs.
The final app.module.ts
file should look like this.
Entities
We have created two entities for the sake of this excercise. Customer entity will use the main db connection and AccessLog entity will use the secondary db connection. For more information about TypeOrm Entity and Repository pattern check out NestJS TypeOrm Docs and TypeOrm Docs.
Use Main DB Connection
In order to have access to the Customer entity TypeOrm functionality we need to import TypeOrm into the Customer module.
And this is how we use it in the Customer service.
Use Secondary DB Connection
As we did for the main connection and the Customer entity we need to import TypeOrm into the AccessLog module, but this time we will also need to pass a connection name to the TypeOrmModule.forFeature([Entities, ...], connectionName)
method.
And this is how we use it in the AccessLog service.
Conclusion
✅ We managed to setup a multiple db configuration with credentials values coming from an environment file.
✅ Defined what connection should each entity use.
✅ With the knowledge of how to add a secondary connection we should be able to add many more as needed.
✅ Learned about the little gotchas when initializing TypeOrm asynchronously.
I really hope this article was helpful.
If you have any feedback or found mistakes, please don’t hesitate to reach out to me.
Top comments (1)
Great article definitely going to be using Nest.js a lot more for backend because it uses native TypeScript.