Sling Academy
Home/Node.js/NestJS: Connecting to Different Databases Based on Routes

NestJS: Connecting to Different Databases Based on Routes

Last updated: February 06, 2024

Overview

In modern web development, the need to interact with multiple databases within a single application is increasingly common. This requirement arises from various business needs, including separating data storage for security reasons, optimizing performance, or simply due to the nature of the data being dealt with. NestJS, a progressive Node.js framework for building efficient and scalable server-side applications, provides a robust system for managing different database connections. In this tutorial, we will explore how to dynamically connect to different databases based on the routes accessed in a NestJS application.

Prerequisites

  1. Basic understanding of TypeScript
  2. Familiarity with NestJS framework
  3. Node.js and npm installed

Setting Up Your NestJS Project

First, let’s create a new NestJS project if you haven’t got one already:

npm i -g @nestjs/cli
nestjs new my-database-project
cd my-database-project

Once your project is set up, ensure that you have the necessary database drivers and ORM libraries installed. For this tutorial, we’ll assume you’re working with TypeORM, a popular choice within NestJS applications:

npm install --save @nestjs/typeorm typeorm

Configuring Multiple Database Connections

Next, let’s configure TypeORM to connect to multiple databases. You’ll need to modify the app.module.ts and set up different connections. Here’s how a basic configuration might look:

// app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      name: 'default', // Default connection
      ... // Other default connection settings
    }),
    TypeOrmModule.forRoot({
      name: 'secondary', // Secondary connection
      ... // Other secondary connection settings
    })
  ],
})
export class AppModule {}

We specify each connection with a unique name to distinguish between them. This setup is critical for accessing and managing these connections dynamically.

Dynamic Database Connection Based on Routes

With the multiple connections configured, we can now focus on dynamically selecting the correct database connection based on the routes accessed. For this purpose, we can leverage NestJS’s middleware capabilities or create custom decorators.

Using Middleware

One straightforward approach is to use middleware to alter the database connection before the request reaches the route handler. Create a middleware that checks the route and switches the TypeORM connection accordingly:

// switch-db.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response } from 'express';
import { getConnectionManager } from 'typeorm';

@Injectable()
export class SwitchDbMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: Function) {
    const connectionManager = getConnectionManager();
    const route = req.path;
    let connectionName = 'default';
    if(route.startsWith('/api/secondary')) connectionName = 'secondary';
    // Ensure the connection is established with the right DB
    connectionManager.get(connectionName).connect().then(() => next());
  }
}

Using Custom Decorators

An alternative and more elegant way to handle this is through custom decorators. You can create a decorator that specifies which database connection a service method should use:

// use-connection.decorator.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const UseConnection = createParamDecorator(
  (connectionName: string, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    request.connectionName = connectionName;
    return connectionName;
  }
);

Then, in your service methods, you can use this decorator to dynamically switch connections:

// my.service.ts
import { Injectable } from '@nestjs/common';
import { UseConnection } from './use-connection.decorator';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

@Injectable()
export class MyService {
  constructor(
    @InjectRepository(MyEntity, 'default') private defaultRepo: Repository<MyEntity>,
    @InjectRepository(MyEntity, 'secondary') private secondaryRepo: Repository<MyEntity>
  ) {}

  @UseConnection('secondary')
  async findInSecondaryDB() {
    return this.secondaryRepo.find();
  }
}

This approach is cleaner and offers more flexibility. It also encapsulates the connection logic neatly within decorators, keeping your services concise and focused on business logic.

Conclusion

Throughout this tutorial, we’ve explored how to set up and dynamically switch between multiple database connections in a NestJS application based on routes. While we focused on a couple of strategies – middleware and custom decorators – the concepts can adapt to fit a wide variety of use cases. NestJS’s modular and flexible ecosystem makes it an excellent choice for complex applications that require interactions with multiple databases.

Remember, managing multiple connections can introduce complexity to your application, so it’s essential to thoroughly test your connection-switching logic to ensure data integrity and application stability. Happy coding!

Next Article: Mastering NestJS CLI: A Practical Guide

Previous Article: How to Implement Rate Limiting in NestJS

Series: Nest.js Tutorials: From Basics to Advanced

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates