Global Modules

Available Everywhere — Use Sparingly

Global Modules

`@Global()` makes a module's exports visible in every other module without an explicit import. It's a powerful escape valve, with real downsides.

4 min read Level 2/5 #nestjs#modules#global
What you'll learn
  • Mark a module @Global to expose its providers everywhere
  • Recognize the trade-off (loose coupling becomes implicit)
  • Pick the right candidates — config, logger, database

By default, a module can only inject providers from modules it explicitly imports. @Global() lifts that rule — once the global module is imported once anywhere, its exports are available everywhere.

Marking a Module Global

Add the decorator above @Module. That’s it.

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

@Global()
@Module({
  providers: [LoggerService],
  exports: [LoggerService],
})
export class LoggerModule {}

Now any feature can inject LoggerService without listing LoggerModule in its imports:

@Module({
  controllers: [UsersController],
  providers: [UsersService], // UsersService can inject LoggerService for free
})
export class UsersModule {}

You still have to import the global module once in the root (AppModule) to register it.

Dynamic + Global

Most real-world global modules are also dynamic — they take config in forRoot(). Set global: true on the returned DynamicModule:

static forRoot(options: ConfigOptions): DynamicModule {
  return {
    module: ConfigModule,
    global: true,
    providers: [{ provide: 'CONFIG_OPTS', useValue: options }, ConfigService],
    exports: [ConfigService],
  };
}

The Trade-Off

Global modules feel like a free lunch — fewer imports, less typing. The hidden cost: dependencies become invisible. Open a feature module’s file and you can’t tell what it really uses; tooling can’t either.

That makes a few things harder:

  • Refactoring. You can’t safely delete a “global” provider without searching the whole codebase.
  • Testing. Test modules don’t get the global registration automatically; you’ll need to add it explicitly anyway.
  • Onboarding. New developers see a service appear out of thin air.

When Global Makes Sense

A small, well-defined list:

ModuleWhy global is OK
ConfigModuleTruly every feature needs it
LoggerModuleSame — and you want a uniform interface
DatabaseModuleOne connection, used everywhere
EventEmitterModuleCross-cutting pub/sub

If you find yourself reaching for @Global on a feature module, that’s a sign the dependency boundary isn’t right yet — extract the truly shared bits and keep the feature module non-global.

Structuring Feature Modules →