Why Modules Are the Most Important Concept in NestJS
In Express, structure is optional. In NestJS, structure is enforced.
Modules are the unit of architecture in NestJS.
Everything else – controllers, services, guards – lives inside a module.
Think of modules are:
Bounded contexts + dependency containers
What a Module Really Is
At runtime, a NestJS module is:
- A dependency scope
- A visibility boundary
- A configuration unit
@Module({
imports: [],
providers: [],
controllers: [],
exports: [],
})
export class UserModule {}This metadata is consumed during startup, not runtime.
Root Modules vs Feature Modules
Root Module (AppModule)
Every NestJS app has a root module which is the entry point of the application.
- Entry point for module discovery
- Composes the entire application
- Contains no business logic
Feature Module
Feature modules organize code by domain.
- Encapsulates a domain or capability
- Own their controllers and services
- Export only what others need
Module Structure
@Module({
imports: [], // other modules
controllers: [], // route handlers
providers: [], // services
exports: [], // shared providers
})The imports Array – Dependency Declaration
When a module imports another module, it is saying:
I depend on the public API of that module.
Example:
@Module({
imports: [UserModule],
})
export class OrderModule {}This does not mean:
- Access to all providers
- Access to private internals
Only exported providers are visible.
The providers Array – Ownership Matters
Providers declared in a module are:
- Owned by that module
- Instantiated in that module's scope
@Module({
providers: [UserService],
})
export class UserModule {}Ownership implies:
- Lifecycle responsibility
- Initialization responsibility
The exports Array – Public API of a Module
Exports define what other modules are allowed to use.
@Module({
providers: [UserService],
exports: [UserService],
})
export class UserModule {}Think of exports as:
The public interface of a module
Everything else is private.
Your First Module
Let's create a simple module.
Step 1: Generate the Module
# The magic command that creates everything for you
nest generate module books
# What this creates:
# - books/books.module.ts (the module file)
# - Updates app.module.ts to import the new moduleStep 2: Look Inside the Generated Module
// books/books.module.ts - Your brand new module!
import { Module } from '@nestjs/common';
@Module({}) // Empty for now - we'll fill it up
export class BooksModule {}It's empty. That's okay – Think of it as an empty box. Let's add some contents.
Connecting Modules Together
To use one module inside another:
@Module({
imports: [UsersModule],
})
export class AppModule {}Sharing Providers Between Modules
By default, providers are private to a module.
To share them:
Step 1: Export provider
@Module({
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}Step 2: Import Module
@Module({
imports: [UsersModule],
})
export class OrdersModule {}Now UsersService is usable in OrdersModule.
Global Modules
Some modules should be available everywhere.
Example:
import { Global, Module } from '@nestjs/common';
@Global()
@Module({
providers: [ConfigService],
exports: [ConfigService],
})
export class ConfigModule {}No need to import it repeatedly.
Leave a comment
Your email address will not be published. Required fields are marked *


