# Modules

> Source: https://learn-nestjs.com/modules/
> Part of Learn NestJS, free to read.

A module groups related code and declares its boundary. Everything in a Nest application belongs to exactly one module, and modules decide what is visible outside themselves.

```ts src/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  imports: [],                  // other modules whose exports we need
  controllers: [UsersController],
  providers: [UsersService],    // constructible and injectable inside this module
  exports: [UsersService],      // ...and available to modules that import us
})
export class UsersModule {}
```

The key rule: **a provider is private to its module unless it is exported.** If `OrdersService` needs `UsersService`, then `UsersModule` must export it and `OrdersModule` must import `UsersModule`. There is no ambient global scope.

That constraint is the point. It makes the dependency graph explicit and it means you can see, from one file, everything a feature depends on.

## Feature modules

The standard layout is one module per domain concept:

```text
src/
  app.module.ts
  users/
    users.module.ts
    users.controller.ts
    users.service.ts
    dto/
    entities/
  orders/
    orders.module.ts
    ...
```

```ts src/app.module.ts
@Module({
  imports: [UsersModule, OrdersModule],
})
export class AppModule {}
```

## Shared modules

A module exporting a provider is a singleton across the whole application by default. Import it in two places and both get the same instance.

```ts src/database/database.module.ts
@Module({
  providers: [PrismaService],
  exports: [PrismaService],
})
export class DatabaseModule {}
```

## Dynamic modules

When a module needs configuration, use the `forRoot` / `forRootAsync` convention.

```ts
@Module({})
export class MailModule {
  static forRoot(options: MailOptions): DynamicModule {
    return {
      module: MailModule,
      providers: [
        { provide: MAIL_OPTIONS, useValue: options },
        MailService,
      ],
      exports: [MailService],
    };
  }
}
```

```ts
@Module({
  imports: [MailModule.forRoot({ apiKey: process.env.MAIL_KEY! })],
})
export class AppModule {}
```

## Global modules

`@Global()` makes a module's exports available everywhere without importing it.

```ts
@Global()
@Module({ providers: [ConfigService], exports: [ConfigService] })
export class ConfigModule {}
```

:::warn Use this sparingly
`@Global()` removes exactly the property that makes modules useful — the explicit dependency edge. Config and logging are reasonable; anything domain-specific is not. A codebase where everything is global is an Express app with extra decorators.
:::

## Circular dependencies

Two modules importing each other is usually a design smell, but when it is genuinely needed:

```ts
@Module({ imports: [forwardRef(() => OrdersModule)] })
export class UsersModule {}
```

Before reaching for `forwardRef`, ask whether the shared piece belongs in a third module that both import. That is the right answer about eighty percent of the time.

## Common questions

### How granular should modules be?

One per bounded domain concept, not one per file. `UsersModule` containing the controller, service, DTOs and entities is right. Splitting a service into its own module because it felt big is not.

### Why does my provider say it cannot be resolved?

Almost always one of two things: the provider is not in the `providers` array of any module in scope, or it is in another module that does not `export` it. The error message names the missing token and the module it was requested from — read both halves.

### Is `forwardRef` bad?

It is a signal, not a sin. It usually means two modules share a concept that wants extracting into a third. If you have more than one or two, look at the shape of your domain rather than adding more.
