NestJS Shared Modules

I am reading Modules in NestJS official documentation and I wanted to try shared modules.

So, I have the following structure for my application:

src
├── cats
│   ├── cats.controller.ts
|   ├── cats.module.ts
|   └── cats.service.ts
├── users
│   ├── users.controller.ts
|   ├── users.module.ts
|   └── users.service.ts
├── app.controller.ts
├── app.module.ts
├── app.service.ts
└── main.ts

I understand that modules are singletons and shared modules by default in NestJS so long as you export its service and import its module to another module. Read it here.

On my end, I want to see whether it is true and so I did not follow the documentation and instead imported directly the cats.service.ts into another service called users.service.ts, like the below:

src/users/users.controller.ts

import { Controller, Get } from '@nestjs/common';
import { UsersService } from './user.service';

@Controller('users')
export class UserController {
 constructor(private readonly usersService: UsersService) {}

  @Get('get-cats')
  getCats() {
    return this.usersService.getCats();
  }
}

src/users/users.service.ts, I imported it here directly.

import { Inject, Injectable } from '@nestjs/common';
import { CatsService } from 'src/cats/cats.service.ts';


@Injectable()
export class UsersService {

  getCats() {
    return new CatsService().findAll();
  }
}

However, it seems that it works fine because I can actually see all the cats when I go to the path localhost:3000/users/get-cats.

I am expecting to get something like must import x inside y to access this service or like any error that prevents me from doing so. Is there something that I missed or did not understand?

Edit:

What I did not follow is this particular line in the official documentation:

In order to do that, we first need to export the CatsService provider by adding it to the module's exports array. Now any module that imports the CatsModule has access to the CatsService and will share the same instance with all other modules that import it as well.

>Solution :

You are right, that is totally possible. But the question is whether it is a good idea to do this?

You basically just created a new instance of the CatsService class. Of course you can do that. There is (obviously) nothing to stop you from doing this plain Typescript logic. Nevertheless CatsService will not be a singleton which can be injected in other services. You have created your own instance and do not benefit from dependency injection (provided by NestJS) anymore.

What happens if you want to pass dependencies to your CatsService constructor? You would have to pass them also in the place where you are creating the CatsService yourself (new CatsService(...dependencies)).

Basically NestJS can be seen as a framework in order to handle dependencies based on the annotations passed to classes. You are free to just ignore the annotations and handle dependency injection yourself. Nevertheless this would result in getting rid of the handy features NestJS provides. This way you would also need to handle the logic of creating singletons as well (if you want to ensure that these classes are instantiated as singletons).

Example:

Calling new CatsService() multiple times in your application would lead to many instances of this class being created. Passing the service to your constructor like constructor(catsService: CatsService) would lead to one instance being created and then this single instance will be injected into different other objects.

Leave a Reply