Group Related Code Into a Self-Contained Unit
Modules — Nest's Composition Unit
A module is a class decorated with `@Module` that organizes a feature's controllers, providers, and dependencies.
What you'll learn
- Create a module with `@Module`
- Understand imports, controllers, providers, and exports
- Import one module into another
A module is how Nest groups related code. Every Nest app has at least
one (the root AppModule), and feature modules are how you scale up
without turning your codebase into a spaghetti.
The Anatomy of @Module
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
imports: [], // other modules this one depends on
controllers: [UsersController], // HTTP entry points
providers: [UsersService], // injectable classes
exports: [UsersService], // things other modules can import
})
export class UsersModule {} Four arrays, each with a job:
- imports — other modules whose exports you want to use.
- controllers — classes that handle HTTP routes for this feature.
- providers — services, repositories, factories — anything injectable.
- exports — providers that other modules can use after importing this one.
Wiring a Feature Module Into the Root
Generate the feature, then add it to AppModule.imports:
nest g module users
nest g controller users
nest g service users import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
@Module({
imports: [UsersModule],
})
export class AppModule {} Now everything inside UsersModule boots with the app, and any provider
listed in its exports is injectable from anywhere that imports it.
Encapsulation Is Real
A provider that isn’t exported stays private. If UsersService isn’t in
UsersModule’s exports, no other module can inject it — even if they
import UsersModule. This is the same encapsulation you’d build by hand
with folders and barrel files, except enforced by the framework.
Shared & Dynamic Modules
For cross-cutting concerns (config, database, logger) you make a
shared module and import it everywhere. Some modules expose a static
method like forRoot() to accept configuration — those are called
dynamic modules. We’ll see them when we wire up databases.