How to make a module available to other modules or global without importing it in Nestjs?

February 2, 2023 - 6 min read

To make a module available to other modules without importing in Nestjs is to make the module global by using the @Global() decorator function from the @nestjs/common module and then defining it just above the module class that you need to use without importing it.

TL;DR

Filepath: src/cats/cats.module.ts

import { Module, Global } from "@nestjs/common";

import { CatsService } from "./cats.service";

// make the `CatsModule` global using the `@Global()`
// decorator function so that this module can
// be used without importing it explicitly in other modules.
@Global()
@Module({
  providers: [CatsService], // <- add the provider here
  exports: [CatsService], // <- export the provider here
})
export class CatsModule {}

Filepath: src/cats/cats.service.ts

import { Injectable } from "@nestjs/common";

@Injectable()
export class CatsService {
  // returns cat names
  getCatNames() {
    return ["Luna", "Milo", "Simba", "Oliver", "Loki"];
  }
}

Filepath: src/customer/customer.service.ts

import { Injectable } from "@nestjs/common";

import { CatsService } from "../cats/cats.service";

@Injectable()
export class CustomerService {
  // declare and initialize an instance of
  // the `CatsService` service provider class
  constructor(private catsService: CatsService) {}

  getCatNames() {
    // use the `getCatNames()` method from the `CatsService`
    // class to get the list of all the cat names.
    return this.catsService.getCatNames();
  }
}

Filepath: src/customer/customer.controller.ts

import { Controller, Get } from "@nestjs/common";

import { CustomerService } from "./customer.service";

// make a `/customer` base api endpoint
@Controller("/customers")
export class CustomerController {
  constructor(private customerService: CustomerService) {}

  // adds a `GET` API of `/cats` to the
  // `/customer` base endpoint resulting in
  // `/customer/cats` API endpoint.
  @Get("/cats")
  getCatNames() {
    return this.customerService.getCatNames();
  }
}

Filepath: src/customer/customer.module.ts

import { Module } from "@nestjs/common";

import { CustomerController } from "./customer.controller";

import { CustomerService } from "./customer.service";

@Module({
  controllers: [CustomerController], // <- add the controller here
  providers: [CustomerService], // <- add the provider here
})
export class CustomerModule {}

Filepath: src/app.module.ts

import { Module } from "@nestjs/common";

import { CustomerModule } from "./customer/customer.module";
import { CatsModule } from "./cats/cats.module";

@Module({
  imports: [CustomerModule, CatsModule], // <- add the global and the customer modules here
})
export class AppModule {}

For example, let's say we have 2 modules where one class is called CatsModule and the other is called CustomersModule. We aim to use the CatsModule without importing it in the CustomersModule.

To do that, let's first create a CatService service provider class with a method called getCatNames(). The getCatNames() method will return all the names of the cats currently present in the system.

The service provider class will look like this,

Filepath: src/cats/cats.service.ts

import { Injectable } from "@nestjs/common";

@Injectable()
export class CatsService {
  // returns cat names
  getCatNames() {
    return ["Luna", "Milo", "Simba", "Oliver", "Loki"];
  }
}

Secondly, let's create the CatsModule class that exports the service provider CatService service provider class.

Filepath: src/cats/cats.module.ts

import { Module } from "@nestjs/common";

import { CatsService } from "./cats.service";

@Module({
  providers: [CatsService], // <- add the provider here
  exports: [CatsService], // <- export the provider here
})
export class CatsModule {}

Now we need to make the CatsModule class global using the @Global() decorator function from the @nestjs/common module and use it just before the @Module() decorator function of the CatsModule module class.

It can be done like this,

Filepath: src/cats/cats.module.ts

import { Module, Global } from "@nestjs/common";

import { CatsService } from "./cats.service";

// make the `CatsModule` global using the `@Global()`
// decorator function so that this module can
// be used without importing it explicitly in other modules.
@Global()
@Module({
  providers: [CatsService], // <- add the provider here
  exports: [CatsService], // <- export the provider here
})
export class CatsModule {}

The CatsModule module is now global and can be used without importing into other modules.

Now let's make a GET API endpoint called /customers/cats in the CustomersModule module that lists all the cat's names from the CatsModules.

To know more about a GET API endpoint see the blog on How to make a simple GET request or an API endpoint in Nestjs?.

The API CustomerModule, CustomerController, and the CustomerService classes look like this,

Filepath: src/customer/customer.module.ts

import { Module } from "@nestjs/common";

import { CustomerController } from "./customer.controller";

import { CustomerService } from "./customer.service";

@Module({
  controllers: [CustomerController], // <- add the controller here
  providers: [CustomerService], // <- add the provider here
})
export class CustomerModule {}

Filepath: src/customer/customer.controller.ts

import { Controller, Get } from "@nestjs/common";

import { CustomerService } from "./customer.service";

// make a `/customer` base api endpoint
@Controller("/customers")
export class CustomerController {
  constructor(private customerService: CustomerService) {}

  // adds a `GET` API of `/cats` to the
  // `/customer` base endpoint resulting in
  // `/customer/cats` API endpoint.
  @Get("/cats")
  getCatNames() {
    return this.customerService.getCatNames();
  }
}

Filepath: src/customer/customer.service.ts

import { Injectable } from "@nestjs/common";

@Injectable()
export class CustomerService {
  getCatNames() {
    // cool code here
  }
}

We have our /customer/cats GET API endpoint ready.

Finally, we need to use our global CatsModule module in the CustomerService service provider class. To do that all we have to do is declare and initialize a private variable called catsService (this can be anything) in the constructor method of the CustomerService service provider class.

It can be done like this,

Filepath: src/customer/customer.service.ts

import { Injectable } from "@nestjs/common";

import { CatsService } from "../cats/cats.service";

@Injectable()
export class CustomerService {
  // declare and initialize an instance of
  // the `CatsService` service provider class
  constructor(private catsService: CatsService) {}

  getCatNames() {
    // use the `getCatNames()` method from the `CatsService`
    // class to get the list of all the cat names.
    return this.catsService.getCatNames();
  }
}

The thing to note is that since we have declared the CatsModule as the global module, the Nestjs runtime will automatically inject an instance of the CatsModule class otherwise we would have to import the CatsModule in the CustomerModule module declaration file.

Since we have defined the CatsModule as global, we also need to import the CatsModule in the core/root module of the application. In our case, it will be in the src/app.module.ts file.

Filepath: src/app.module.ts

import { Module } from "@nestjs/common";

import { CustomerModule } from "./customer/customer.module";
import { CatsModule } from "./cats/cats.module";

@Module({
  imports: [CustomerModule, CatsModule], // <- add the global and the customer modules here
})
export class AppModule {}

Now if we go to the /customers/cats API endpoint in the browser you can see all the cat names we have added which proves that the global CatsModule is working as expected. Yay 🥳!

See the above code live in codesandbox.

That's all 😃.