Modules
Modules in NestJS v10 are the core mechanism for organizing and managing applications.
Feature Modules
Feature modules are organized around specific functionalities or business domains. For example, a user management module can include all user-related controllers and services.
Creating a Feature Module
Use the Nest CLI to create a feature module:
nest generate module usersThis generates a UsersModule in the src/modules/users/users.module.ts file.
// src/modules/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@Module({
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}Shared Modules
Shared modules contain services and other providers that can be reused across multiple feature modules.
Creating a Shared Module
Use the Nest CLI to create a shared module:
nest generate module commonThis generates a CommonModule in the src/modules/common/common.module.ts file.
// src/modules/common/common.module.ts
import { Module } from '@nestjs/common';
import { CommonService } from './common.service';
@Module({
providers: [CommonService],
exports: [CommonService],
})
export class CommonModule {}Module Re-exporting
To allow other modules to access providers from a specific module, use the exports property.
// src/modules/common/common.module.ts
import { Module } from '@nestjs/common';
import { CommonService } from './common.service';
@Module({
providers: [CommonService],
exports: [CommonService],
})
export class CommonModule {}
// src/modules/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
import { CommonModule } from './common/common.module';
import { UsersController } from './users/users.controller';
import { UsersService } from './users/users.service';
@Module({
imports: [CommonModule], // Import shared module
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}Dependency Injection
Modules enable dependency injection by importing other modules.
// src/modules/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersModule } from './users/users.module';
import { CommonModule } from './common/common.module';
import { UsersController } from './users/users.controller';
import { UsersService } from './users/users.service';
@Module({
imports: [CommonModule], // Import shared module
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}Global Modules
Global modules do not need to be imported into every module that uses them; they can be set as global.
// src/modules/common/common.module.ts
import { Module } from '@nestjs/common';
import { CommonService } from './common.service';
@Module({
providers: [CommonService],
exports: [CommonService],
global: true, // Set as global
})
export class CommonModule {}
// src/app.module.ts
import { Module } from '@nestjs/common';
import { UsersModule } from './modules/users/users.module';
import { CommonModule } from './modules/common/common.module';
@Module({
imports: [CommonModule, UsersModule], // No need to import CommonModule again
})
export class AppModule {}Dynamic Modules
Dynamic modules allow modules to be created dynamically at runtime, which is particularly useful for configuration modules.
Creating a Dynamic Module
// src/modules/config/config.module.ts
import { Module, Global } from '@nestjs/common';
import { ConfigService } from './config.service';
@Global()
@Module({
providers: [ConfigService],
exports: [ConfigService],
})
export class ConfigModule {
static register(options: any): DynamicModule {
return {
module: ConfigModule,
providers: [
{
provide: ConfigService,
useValue: options,
},
],
exports: [ConfigService],
};
}
}Using a Dynamic Module
// src/app.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from './modules/config/config.module';
import { UsersModule } from './modules/users/users.module';
@Module({
imports: [
ConfigModule.register({ environment: process.env.NODE_ENV }), // Dynamic registration
UsersModule,
],
})
export class AppModule {}Shared Module
// src/modules/common/common.module.ts
import { Module } from '@nestjs/common';
import { CommonService } from './common.service';
@Module({
providers: [CommonService],
exports: [CommonService],
})
export class CommonModule {}Feature Module
// src/modules/users/users.module.ts
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
import { CommonModule } from '../common/common.module';
@Module({
imports: [CommonModule],
controllers: [UsersController],
providers: [UsersService],
})
export class UsersModule {}Main Module
// src/app.module.ts
import { Module } from '@nestjs/common';
import { UsersModule } from './modules/users/users.module';
import { CommonModule } from './modules/common/common.module';
@Module({
imports: [CommonModule, UsersModule],
})
export class AppModule {}Middleware
Middleware in NestJS v10 is used to handle specific stages of the HTTP request lifecycle.
Dependency Injection
Middleware can inject dependencies via the constructor, and these dependencies must be part of a module.
// src/middlewares/logging.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class LoggingMiddleware implements NestMiddleware {
constructor(private readonly appService: AppService) {}
use(req: Request, res: Response, next: NextFunction) {
console.log(`Request... URL: ${req.url}`);
next();
}
}
// src/app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggingMiddleware } from './middlewares/logging.middleware';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggingMiddleware).forRoutes('*');
}
}Applying Middleware
Middleware must be applied in the configure method of a module.
// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggingMiddleware } from './middlewares/logging.middleware';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggingMiddleware).forRoutes('*');
}
}Route Wildcards
Wildcards like * can be used to specify a group of routes.
// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggingMiddleware } from './middlewares/logging.middleware';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggingMiddleware).forRoutes('api/*'); // Applies to all routes starting with api
}
}Middleware Consumer
The middleware consumer specifies which routes the middleware applies to.
// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggingMiddleware } from './middlewares/logging.middleware';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggingMiddleware).forRoutes('api/*'); // Applies to all routes starting with api
}
}Excluding Routes
Use the exclude method to exclude specific routes.
// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggingMiddleware } from './middlewares/logging.middleware';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggingMiddleware)
.forRoutes('api/*')
.exclude('api/exclude-me') // Exclude this route
.forRoutes('api/another-route');
}
}Functional Middleware
You can create specialized functional middleware for specific tasks, such as authentication.
// src/middlewares/auth.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class AuthMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
if (!req.headers.authorization) {
res.status(401).send('Unauthorized');
} else {
next();
}
}
}Multiple Middleware
Multiple middleware can be applied to a single route.
// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggingMiddleware } from './middlewares/logging.middleware';
import { AuthMiddleware } from './middlewares/auth.middleware';
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(LoggingMiddleware, AuthMiddleware).forRoutes('api/protected-route');
}
}Global Middleware
Global middleware can be applied to the entire application.
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { LoggingMiddleware } from './middlewares/logging.middleware';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalMiddlewares(new LoggingMiddleware());
await app.listen(3000);
}
bootstrap();



