The site is under development.

NestJS Tutorial

What is NestJS?
NestJS is a progressive Node.js framework for building efficient and scalable server-side applications. It uses TypeScript and combines elements of OOP, FP, and FRP.

// Simple NestJS controller example
import { Controller, Get } from '@nestjs/common';

@Controller('hello')
export class HelloController {
  @Get()
  getHello(): string {
    return 'Hello from NestJS!';
  }
}
      

Core features and philosophy
- Uses TypeScript by default.
- Supports Dependency Injection.
- Modular architecture.
- Uses decorators to define routes, middleware, etc.
- Built on Express (or optionally Fastify).

// Example of dependency injection
@Injectable()
export class CatsService {
  getCats() {
    return ['cat1', 'cat2'];
  }
}
      

Comparison with Express and other frameworks
NestJS builds on Express but adds structure, type safety, and modularity. It’s more opinionated but easier for large apps.

// Express route
app.get('/cats', (req, res) => {
  res.send(['cat1', 'cat2']);
});

// NestJS route (as above)
      

Architecture overview (Modules, Controllers, Services)
- **Modules:** Organize code into logical units.
- **Controllers:** Handle incoming requests.
- **Services:** Handle business logic.

// Example Module
@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}
      

Setting up the development environment
- Install Node.js.
- Install Nest CLI via npm.
- Initialize a new project.

npm i -g @nestjs/cli
nest new project-name
cd project-name
npm run start
      

Installing Nest CLI
The Nest CLI helps scaffold projects, generate components, and manage builds.

npm install -g @nestjs/cli
      

Creating a new project
Use the CLI to create a new NestJS project quickly with all dependencies.

nest new my-nest-app
      

Folder structure overview
- **src/**: source code.
- **main.ts**: entry point.
- **app.module.ts**: root module.
- **app.controller.ts**: root controller.
- **app.service.ts**: root service.
- **node_modules/**: dependencies.
- **package.json**: project config.

my-nest-app/
├── src/
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   └── main.ts
├── package.json
└── nest-cli.json
      

Running the development server
Start your server with:

npm run start
// or for live reload
npm run start:dev
      

Basic configuration with .env
Use `.env` files and the `@nestjs/config` package for environment variables.

// Install config package
npm install @nestjs/config

// In app.module.ts
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [ConfigModule.forRoot()],
})
export class AppModule {}
      

What is a Module?
A module is a class annotated with `@Module()` decorator. It groups controllers and providers related to a feature.

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

@Module({
  controllers: [...],
  providers: [...],
  imports: [...],
  exports: [...],
})
export class FeatureModule {}
      

Creating custom modules
You can create feature modules to organize code by functionality.

nest generate module cats
// or
nest g mo cats
      

Module metadata
The `@Module()` decorator accepts metadata properties:
- `controllers`: Controllers to register.
- `providers`: Services/providers.
- `imports`: Modules imported.
- `exports`: Providers/modules to export.

@Module({
  controllers: [CatsController],
  providers: [CatsService],
  imports: [],
  exports: [CatsService],
})
export class CatsModule {}
      

Importing & exporting modules
Modules can import other modules to use their exported providers.

@Module({
  imports: [CatsModule],
})
export class AppModule {}
      

Feature modules vs global modules
- Feature modules group related features.
- Global modules are shared across the app, often via `@Global()` decorator.

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

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

Understanding controllers
Controllers handle incoming HTTP requests and return responses. They act as the interface between the client and the server logic.

Creating a basic controller
Use the `@Controller()` decorator to define a controller and create methods decorated with route handlers like `@Get()`, `@Post()`, etc.

import { Controller, Get } from '@nestjs/common';

@Controller('cats')
export class CatsController {
  @Get()
  findAll() {
    return 'This action returns all cats';
  }
}
      

Route handling: GET, POST, PUT, DELETE
Use decorators to handle HTTP methods: - `@Get()` to handle GET requests - `@Post()` for POST - `@Put()` for PUT - `@Delete()` for DELETE

@Controller('cats')
export class CatsController {
  @Get()
  findAll() { /* ... */ }

  @Post()
  create() { /* ... */ }

  @Put(':id')
  update(@Param('id') id: string) { /* ... */ }

  @Delete(':id')
  remove(@Param('id') id: string) { /* ... */ }
}
      

Request/response handling
NestJS automatically handles request parsing. Use decorators like `@Body()`, `@Query()`, `@Param()` to access request data.

@Post()
create(@Body() createCatDto) {
  return `Create cat with name ${createCatDto.name}`;
}
      

Route parameters, query parameters, and body parsing
- **Route params:** Extracted via `@Param()`
- **Query params:** Extracted via `@Query()`
- **Body:** Extracted via `@Body()`

@Get(':id')
findOne(@Param('id') id: string) {
  return `Cat #${id}`;
}

@Get()
findByBreed(@Query('breed') breed: string) {
  return `Cats of breed ${breed}`;
}
      

What is a service?
Services contain business logic and can be injected into controllers or other services. They promote code reusability and separation of concerns.

Dependency Injection (DI)
DI is a design pattern where objects are provided their dependencies instead of creating them. NestJS uses DI to manage service lifecycles.

Creating a service and using it in a controller
Use `@Injectable()` decorator for services. Then inject the service into a controller via the constructor.

import { Injectable } from '@nestjs/common';

@Injectable()
export class CatsService {
  private readonly cats = [];

  findAll() {
    return this.cats;
  }
}

import { Controller, Get } from '@nestjs/common';
import { CatsService } from './cats.service';

@Controller('cats')
export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Get()
  findAll() {
    return this.catsService.findAll();
  }
}
      

Singleton pattern in NestJS
Services in NestJS are singletons by default. One instance is created and shared across the app.
Best practices for service design
- Keep services focused on business logic
- Avoid direct HTTP or database code in controllers
- Use interfaces or DTOs for clear contracts
- Write unit tests for services

Overview of DI in NestJS
Dependency Injection lets NestJS create and manage service instances and their dependencies automatically, simplifying architecture.
Providers and tokens
Providers are classes or values that can be injected. Tokens are unique identifiers for providers, which can be class names or custom strings.

{
  provide: 'CUSTOM_TOKEN',
  useClass: CustomService,
}
      

UseClass, UseValue, UseFactory
- **useClass:** Provide a class to be instantiated.
- **useValue:** Provide a fixed value.
- **useFactory:** Provide a factory function that returns the provider.

{
  provide: ConfigService,
  useFactory: () => {
    return new ConfigService(process.env.CONFIG);
  },
}
      

Scoping providers (singleton, transient, request-scoped)
- **Singleton (default):** One instance shared globally.
- **Transient:** New instance created every injection.
- **Request-scoped:** New instance per HTTP request.

@Injectable({ scope: Scope.REQUEST })
export class ScopedService { }
      

What is middleware?
Middleware is code that runs before your route handlers. It can modify requests/responses, perform checks, or add functionality.

// Example: middleware logs each request
function logger(req, res, next) {
  console.log(`${req.method} ${req.url}`);
  next();
}
      

Creating custom middleware
You create a function that takes `req`, `res`, and `next`. Do your logic and call `next()` to continue.

function authMiddleware(req, res, next) {
  if (!req.headers.authorization) {
    res.status(401).send('Unauthorized');
  } else {
    next();
  }
}
      

Applying middleware globally or per route
Global middleware runs for all routes. You can also apply middleware only to specific routes.

// Global
app.use(authMiddleware);

// Specific route
app.get('/profile', authMiddleware, (req, res) => {
  res.send('User Profile');
});
      

Built-in middleware (e.g., body-parser)
Middleware like `body-parser` parses JSON or URL-encoded request bodies so you can access them easily.

const bodyParser = require('body-parser');
app.use(bodyParser.json()); // parses JSON bodies
      

Built-in HTTP exceptions
Frameworks provide standard exceptions for common HTTP errors like 404 Not Found or 500 Internal Server Error.

throw new NotFoundException('Resource not found');
      

Creating custom exceptions
You can define your own exceptions to provide more details or specific behavior.

class CustomException extends HttpException {
  constructor() {
    super('Custom error occurred', 400);
  }
}
      

Global exception filters
Filters let you catch exceptions globally and format responses consistently.

@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: any, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    response.status(500).json({ message: 'Internal server error' });
  }
}
      

Catching errors with @Catch()
Use the `@Catch()` decorator to create filters that catch specific or all exceptions.

@Catch(NotFoundException)
export class NotFoundFilter implements ExceptionFilter {
  catch(exception: NotFoundException, host: ArgumentsHost) {
    // custom logic here
  }
}
      

What is a Pipe?
Pipes transform or validate data before it reaches your route handler. Think of them as middleware but specifically for data processing.

@Query()
getUser(@Param('id', ParseIntPipe) id: number) {
  return this.userService.findById(id);
}
      

Built-in pipes (e.g., ParseIntPipe, ValidationPipe)
- `ParseIntPipe`: converts input to an integer.
- `ValidationPipe`: automatically validates input data based on DTOs.

@UsePipes(new ValidationPipe())
createUser(@Body() createUserDto: CreateUserDto) {
  // validated dto here
}
      

Custom pipes for validation/transformation
You can create custom pipes by implementing the `PipeTransform` interface to handle your own logic.

@Injectable()
export class TrimPipe implements PipeTransform {
  transform(value: any) {
    if (typeof value === 'string') {
      return value.trim();
    }
    return value;
  }
}
      

Applying pipes globally or locally
Pipes can be applied:
- Globally (all routes)
- At controller level
- At method or parameter level

// Global
app.useGlobalPipes(new ValidationPipe());

// Controller
@UsePipes(new ValidationPipe())
@Controller('users')
export class UsersController {}

// Parameter
getUser(@Param('id', ParseIntPipe) id: number) {}
      

What is a Guard?
Guards determine whether a request is allowed to proceed based on logic like authentication or roles. They implement the `CanActivate` interface.

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    return request.headers.authorization === 'valid-token';
  }
}
      

Role-based access control
Guards can check user roles to restrict access to routes.

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private readonly roles: string[]) {}

  canActivate(context: ExecutionContext): boolean {
    const user = context.switchToHttp().getRequest().user;
    return this.roles.includes(user.role);
  }
}
      

Custom guards using CanActivate
Implement `CanActivate` and add your logic to allow or deny access.

@Injectable()
export class CustomGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    // Custom logic here
    return true; // or false
  }
}
      

Using @UseGuards()
Apply guards to controllers or routes with the `@UseGuards()` decorator.

import { Controller, Get, UseGuards } from '@nestjs/common';

@Controller('cats')
@UseGuards(AuthGuard)
export class CatsController {
  @Get()
  findAll() {
    return 'This route is protected by AuthGuard';
  }
}
      

What is an Interceptor?
Interceptors bind extra logic before or after method execution, useful for logging, caching, transforming responses, etc.

import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable {
    console.log('Before handler execution');
    const now = Date.now();
    return next
      .handle()
      .pipe(tap(() => console.log(`After... ${Date.now() - now}ms`)));
  }
}
      

Logging, Caching, Response Mapping
Interceptors can modify outgoing responses or cache results to optimize performance.

// Example: Response mapping interceptor
@Injectable()
export class TransformInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable {
    return next.handle().pipe(
      map(data => ({ data, timestamp: new Date().toISOString() })),
    );
  }
}
      

@UseInterceptors()
Attach interceptors to controllers or routes using this decorator.

import { Controller, Get, UseInterceptors } from '@nestjs/common';

@Controller('cats')
@UseInterceptors(LoggingInterceptor)
export class CatsController {
  @Get()
  findAll() {
    return ['cat1', 'cat2'];
  }
}
      

Creating custom interceptors
Create your own interceptors by implementing `NestInterceptor` and adding custom logic.

@Injectable()
export class CustomInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable {
    // Custom pre-processing
    return next.handle().pipe(
      // Custom post-processing
    );
  }
}
      

Using class-validator and class-transformer
These libraries help you define validation rules on DTOs and transform plain objects into class instances.

import { IsString, IsEmail } from 'class-validator';

export class CreateUserDto {
  @IsString()
  name: string;

  @IsEmail()
  email: string;
}
      

DTOs (Data Transfer Objects)
DTOs are classes defining the shape of data sent over the network or between layers.

export class UpdateUserDto {
  @IsString()
  name?: string;

  @IsEmail()
  email?: string;
}
      

NestJS ValidationPipe
Use the built-in `ValidationPipe` to automatically validate incoming requests against DTOs.

import { ValidationPipe } from '@nestjs/common';

app.useGlobalPipes(new ValidationPipe());
      

Handling validation errors
When validation fails, NestJS sends detailed error messages back to the client automatically.

// Example error response
{
  "statusCode": 400,
  "message": [
    "name must be a string",
    "email must be an email"
  ],
  "error": "Bad Request"
}
      

Using @nestjs/config
The `@nestjs/config` package helps manage environment variables and app settings in a clean way.

// Install
npm install @nestjs/config

// In app.module.ts
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [ConfigModule.forRoot()],
})
export class AppModule {}
      

Managing environment variables
Put variables in `.env` file and access them using the ConfigService.

// .env file
DATABASE_HOST=localhost
DATABASE_PORT=5432
      

// Usage in service
import { ConfigService } from '@nestjs/config';

constructor(private configService: ConfigService) {}

const dbHost = this.configService.get('DATABASE_HOST');
      

Typed configuration
Create a config schema or interface for type safety.

interface EnvConfig {
  DATABASE_HOST: string;
  DATABASE_PORT: number;
}

const config = () => ({
  DATABASE_HOST: process.env.DATABASE_HOST,
  DATABASE_PORT: parseInt(process.env.DATABASE_PORT, 10),
});
      

Configuring different environments (dev/prod)
Use multiple `.env` files like `.env.development`, `.env.production` and load them conditionally.

ConfigModule.forRoot({
  envFilePath: `.env.${process.env.NODE_ENV || 'development'}`,
});
      

Using the built-in Logger
NestJS provides a `Logger` class for logging messages.

import { Logger } from '@nestjs/common';

const logger = new Logger('MyApp');

logger.log('This is a log message');
logger.error('This is an error');
logger.warn('This is a warning');
      

Creating custom loggers
You can extend the Logger class to customize log behavior.

import { Logger } from '@nestjs/common';

export class MyLogger extends Logger {
  log(message: string) {
    // custom behavior
    super.log(message);
  }
}
      

Logging levels
NestJS supports different log levels: `log`, `error`, `warn`, `debug`, and `verbose`.
Third-party loggers (e.g., Winston)
Use Winston or similar libraries for advanced logging features like transports, formats, and external services.

// Example with Winston integration
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';

@Module({
  imports: [
    WinstonModule.forRoot({
      transports: [
        new winston.transports.Console(),
        new winston.transports.File({ filename: 'combined.log' }),
      ],
    }),
  ],
})
export class AppModule {}
      

TypeORM integration
TypeORM is an ORM for TypeScript and JavaScript supporting many databases. NestJS has tight integration.

// Install
npm install --save @nestjs/typeorm typeorm pg

// Setup in app.module.ts
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'user',
      password: 'pass',
      database: 'mydb',
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true,
    }),
  ],
})
export class AppModule {}
      

Sequelize integration
Sequelize is another ORM option. NestJS supports it via a dedicated package.

// Install
npm install --save @nestjs/sequelize sequelize sequelize-typescript pg

// Setup in app.module.ts
import { SequelizeModule } from '@nestjs/sequelize';

@Module({
  imports: [
    SequelizeModule.forRoot({
      dialect: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'user',
      password: 'pass',
      database: 'mydb',
      models: [User],
      autoLoadModels: true,
    }),
  ],
})
export class AppModule {}
      

MongoDB with Mongoose
For NoSQL, NestJS supports Mongoose ODM.

// Install
npm install --save @nestjs/mongoose mongoose

// Setup
import { MongooseModule } from '@nestjs/mongoose';

@Module({
  imports: [
    MongooseModule.forRoot('mongodb://localhost/nest'),
  ],
})
export class AppModule {}
      

Repository Pattern
TypeORM and Sequelize support repositories that abstract DB operations.

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository,
  ) {}

  findAll() {
    return this.userRepository.find();
  }
}
      

Models, Entities, Schemas
- **Entities** (TypeORM): Classes mapped to DB tables.
- **Models** (Sequelize): Similar ORM class.
- **Schemas** (Mongoose): Define structure for MongoDB collections.

// TypeORM entity example
@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;
}
      

JWT Authentication
JSON Web Tokens (JWT) are used to securely transmit user information between client and server. The server issues a token after login, and the client sends it with requests.

const jwt = require('jsonwebtoken');
const token = jwt.sign({ userId: 123 }, 'your-secret-key', { expiresIn: '1h' });
      

Passport.js integration
Passport.js is a popular authentication middleware for Node.js, supporting strategies like JWT, OAuth, and local username/password.

const passport = require('passport');
const JwtStrategy = require('passport-jwt').Strategy;

passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
  User.findById(jwt_payload.userId)
    .then(user => done(null, user))
    .catch(err => done(err, false));
}));
      

Sessions vs Tokens
- **Sessions** store login info on the server; client holds a session ID cookie.
- **Tokens** (like JWT) store info in the token itself, allowing stateless authentication.

// Sessions example with express-session
app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: true }));
      

Protecting routes
Middleware or guards check if the user is authenticated before allowing access to protected routes.

app.get('/profile', passport.authenticate('jwt', { session: false }), (req, res) => {
  res.send('Protected profile page');
});
      

Refresh tokens
Refresh tokens are long-lived tokens that allow the client to get new access tokens without re-logging in, improving security and user experience.

// Issue refresh token alongside access token
const refreshToken = jwt.sign({ userId: 123 }, 'refresh-secret', { expiresIn: '7d' });
      

Role-based access control
Access is granted based on user roles (e.g., admin, editor, viewer). Define roles and check them before allowing actions.

function checkRole(role) {
  return (req, res, next) => {
    if (req.user.role === role) {
      next();
    } else {
      res.status(403).send('Forbidden');
    }
  };
}
      

Policies and permissions
Policies define detailed permissions for actions, often more granular than roles.

// Example policy
const canEditPost = (user, post) => user.id === post.authorId || user.role === 'admin';
      

Combining with guards
Guards or middleware enforce authorization by applying role and policy checks before handling requests.

app.get('/admin', passport.authenticate('jwt', { session: false }), checkRole('admin'), (req, res) => {
  res.send('Welcome Admin');
});
      

WebSocketGateway
In frameworks like NestJS, `WebSocketGateway` decorates a class to handle real-time socket connections.

@WebSocketGateway()
export class EventsGateway {
  @WebSocketServer()
  server;
}
      

Using @SubscribeMessage()
Decorate methods with `@SubscribeMessage()` to listen for specific messages from clients.

@SubscribeMessage('message')
handleMessage(client: Socket, payload: any) {
  this.server.emit('message', payload);
}
      

Broadcasting events
Use the server instance to send messages to all or specific clients.

this.server.emit('eventName', data); // broadcast to all connected clients
      

Integration with Socket.IO
Many real-time implementations use Socket.IO, which supports rooms, namespaces, and fallback options.

import { Server } from 'socket.io';
const io = new Server(server);

io.on('connection', socket => {
  socket.on('chat', msg => {
    io.emit('chat', msg);
  });
});
      

Installing GraphQL module
To use GraphQL in your project, install the core GraphQL package and any integration libraries (e.g., Apollo Server or NestJS GraphQL module).

npm install graphql @nestjs/graphql apollo-server-express
      

Code-first vs Schema-first
- **Code-first:** Define GraphQL schema using code (classes, decorators). Easier for TypeScript users.
- **Schema-first:** Write schema in GraphQL SDL files and implement resolvers separately.

// Code-first example (NestJS):
@ObjectType()
class User {
  @Field()
  name: string;
}
      

Queries, Mutations, Resolvers
- **Queries:** Read data.
- **Mutations:** Modify data.
- **Resolvers:** Functions that return data for queries or mutations.

@Resolver()
export class UserResolver {
  @Query(() => String)
  hello() {
    return 'Hello GraphQL';
  }
}
      

GraphQL Subscriptions
Subscriptions allow real-time data updates using WebSockets.

@Subscription(() => Message)
messageAdded() {
  // logic for realtime message updates
}
      

Versioning
Maintain API versions to avoid breaking changes for clients. Common patterns include URI versioning (e.g., `/api/v1/...`) or header-based versioning.

// URI versioning example
GET /api/v1/users
      

Pagination
Return data in chunks instead of all at once for performance. Common approaches: offset-limit or cursor-based pagination.

// Query params example
GET /users?limit=10&offset=20
      

HATEOAS
Hypermedia as the Engine of Application State means responses include links to related actions or resources for discoverability.

{
  "users": [...],
  "links": {
    "next": "/api/v1/users?offset=20&limit=10"
  }
}
      

Status codes and error handling
Use proper HTTP status codes (200, 201, 400, 404, 500) and return consistent error messages.

HTTP/1.1 404 Not Found
{
  "error": "User not found"
}
      

Unit testing with Jest
Jest is a popular testing framework for JavaScript and TypeScript. Unit tests check individual functions or classes for correctness.

test('adds 1 + 2 to equal 3', () => {
  expect(1 + 2).toBe(3);
});
      

Testing controllers, services, guards
Test each layer separately: controllers handle requests, services contain business logic, and guards enforce security.

// Example testing a service method
describe('UserService', () => {
  it('should return a user by ID', () => {
    // test code here
  });
});
      

End-to-end (E2E) testing
E2E tests simulate real user scenarios by running the entire app and verifying workflows from start to finish.

// Example with Jest and Supertest
describe('AppController (e2e)', () => {
  it('/GET users', () => {
    return request(app.getHttpServer())
      .get('/users')
      .expect(200)
      .expect(response => {
        expect(response.body).toBeInstanceOf(Array);
      });
  });
});
      

Mocks and spies
Use mocks to simulate dependencies and spies to track function calls during tests.

const mockUserService = {
  findUser: jest.fn().mockReturnValue({ id: 1, name: 'Test User' }),
};
      

Using @nestjs/schedule
NestJS provides `@nestjs/schedule` to easily set up scheduled tasks like cron jobs and intervals.

import { Injectable } from '@nestjs/common';
import { Cron, Interval, Timeout } from '@nestjs/schedule';

@Injectable()
export class TasksService {

  @Cron('45 * * * * *')
  handleCron() {
    console.log('Called every minute at second 45');
  }

  @Interval(10000)
  handleInterval() {
    console.log('Called every 10 seconds');
  }

  @Timeout(5000)
  handleTimeout() {
    console.log('Called once after 5 seconds');
  }
}
      

Cron Jobs and Intervals
- **Cron jobs** run at specific times using cron expressions.
- **Intervals** run repeatedly after a fixed delay.

// Cron example: every day at midnight
@Cron('0 0 0 * * *')
handleDailyTask() {
  // Do daily task
}

// Interval example: every 5 minutes
@Interval(300000)
handleRepeatTask() {
  // Do repeated task
}
      

Delayed Jobs
Using `@Timeout`, you can schedule a one-time delayed task.

@Timeout(60000)
handleDelayedTask() {
  console.log('Runs once after 1 minute');
}
      

Canceling Jobs Dynamically
You can inject `SchedulerRegistry` to add, get, or delete scheduled jobs dynamically at runtime.

import { SchedulerRegistry } from '@nestjs/schedule';

constructor(private schedulerRegistry: SchedulerRegistry) {}

cancelJob(name: string) {
  const job = this.schedulerRegistry.getCronJob(name);
  job.stop();
}
      

Using Bull (Redis-based)
Bull is a popular Redis-based library for managing queues and background jobs in Node.js/NestJS.

import { BullModule } from '@nestjs/bull';

@Module({
  imports: [
    BullModule.forRoot({
      redis: {
        host: 'localhost',
        port: 6379,
      },
    }),
    BullModule.registerQueue({
      name: 'email',
    }),
  ],
})
export class AppModule {}
      

Producers and Consumers
- **Producer:** Adds jobs to the queue.
- **Consumer:** Processes jobs from the queue.

// Producer - add job
await this.emailQueue.add({ to: 'user@example.com', subject: 'Hello!' });

// Consumer - process job
@Processor('email')
export class EmailProcessor {
  @Process()
  async handleEmailJob(job: Job) {
    console.log('Sending email to', job.data.to);
    // send email logic
  }
}
      

Job Retries and Delays
Jobs can be retried automatically on failure or delayed to run later.

// Add job with delay and retries
await this.emailQueue.add(
  { to: 'user@example.com' },
  {
    delay: 60000, // wait 60 seconds
    attempts: 3,  // retry 3 times if failed
  },
);
      

Queue Events
You can listen to queue events like completed, failed, or stalled.

this.emailQueue.on('completed', (job) => {
  console.log(`Job ${job.id} completed!`);
});

this.emailQueue.on('failed', (job, err) => {
  console.log(`Job ${job.id} failed with error ${err.message}`);
});
      

Using Multer
Multer is a middleware for handling `multipart/form-data` (file uploads) in Node.js/NestJS.

import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';

@Controller('upload')
export class UploadController {

  @Post()
  @UseInterceptors(FileInterceptor('file'))
  uploadFile(@UploadedFile() file: Express.Multer.File) {
    console.log(file);
    return { message: 'File uploaded successfully!' };
  }
}
      

Uploading Images and Files
You can accept files like images or documents through forms or API clients.

// HTML form example
<form method="POST" enctype="multipart/form-data" action="/upload">
  <input type="file" name="file" />
  <button type="submit">Upload</button>
</form>
      

Streaming Files
For large files, streaming prevents loading the entire file in memory.

@Post('stream')
@UseInterceptors(FileInterceptor('file'))
uploadStream(@UploadedFile() file: Express.Multer.File) {
  const stream = file.stream;
  // Process stream data chunk by chunk
}
      

Validating File Types and Sizes
Use Multer options to filter allowed file types and limit size.

@UseInterceptors(FileInterceptor('file', {
  limits: { fileSize: 2 * 1024 * 1024 }, // 2MB max
  fileFilter: (req, file, cb) => {
    if (!file.mimetype.match(/\/(jpg|jpeg|png|gif)$/)) {
      return cb(new Error('Only images are allowed!'), false);
    }
    cb(null, true);
  }
}))
      

Using @nestjs/cache-manager
NestJS provides a cache module built on top of `cache-manager`. It simplifies caching data.

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

@Module({
  imports: [CacheModule.register()],
})
export class AppModule {}
      

In-memory cache
The default cache store is in-memory, which is fast but not persistent or shared across instances.

import { Injectable, Cacheable } from '@nestjs/common';

@Injectable()
export class CatsService {
  @Cacheable()
  getCats() {
    // This result will be cached in memory
  }
}
      

Redis as a cache store
Redis is popular for distributed caching. You can configure NestJS cache to use Redis.

CacheModule.register({
  store: require('cache-manager-redis-store'),
  host: 'localhost',
  port: 6379,
});
      

Caching responses and requests
You can cache expensive responses or database results to improve performance.

import { CacheInterceptor, UseInterceptors, Controller, Get } from '@nestjs/common';

@Controller('cats')
@UseInterceptors(CacheInterceptor)
export class CatsController {
  @Get()
  findAll() {
    // Response will be cached automatically
    return ['cat1', 'cat2'];
  }
}
      

Helmet integration
Helmet helps secure Express apps by setting HTTP headers.

import * as helmet from 'helmet';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(helmet());
  await app.listen(3000);
}
bootstrap();
      

CSRF/XSS protection
Use libraries or middlewares to prevent Cross-Site Request Forgery and Cross-Site Scripting attacks.

// Example: Using csurf middleware for CSRF protection
import * as csurf from 'csurf';

app.use(csurf());
      

Rate limiting
Protect your API from abuse by limiting the number of requests per IP.

import { ThrottlerModule } from '@nestjs/throttler';

@Module({
  imports: [
    ThrottlerModule.forRoot({
      ttl: 60,
      limit: 10,
    }),
  ],
})
export class AppModule {}
      

API key protection
Implement API key validation in guards or middleware to restrict access.

@Injectable()
export class ApiKeyGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    return request.headers['x-api-key'] === 'my-secret-key';
  }
}
      

Installing i18n module
Use the `nestjs-i18n` package to add internationalization support.

npm install nestjs-i18n

import { I18nModule } from 'nestjs-i18n';

@Module({
  imports: [
    I18nModule.forRoot({
      fallbackLanguage: 'en',
      loaderOptions: {
        path: path.join(__dirname, '/i18n/'),
        watch: true,
      },
    }),
  ],
})
export class AppModule {}
      

Managing translation files
Store translations in JSON or YAML files in a directory (e.g., `/i18n/en.json`).

{
  "HELLO": "Hello",
  "WELCOME": "Welcome to our app"
}
      

Dynamic language switching
Switch language based on user preferences or request headers.

@Get()
async hello(@I18nLang() lang: string, @I18n() i18n: I18nService) {
  return i18n.t('HELLO', { lang });
}
      

Using @nestjs/swagger
The `@nestjs/swagger` package generates OpenAPI (Swagger) docs automatically from your code.

// Install
npm install --save @nestjs/swagger swagger-ui-express

// main.ts setup
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';

const config = new DocumentBuilder()
  .setTitle('My API')
  .setDescription('API description')
  .setVersion('1.0')
  .build();

const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
      

Documenting routes
Use decorators like `@ApiTags()`, `@ApiOperation()`, `@ApiResponse()` to describe controllers and endpoints.

import { Controller, Get } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';

@ApiTags('cats')
@Controller('cats')
export class CatsController {
  @Get()
  @ApiOperation({ summary: 'Get all cats' })
  @ApiResponse({ status: 200, description: 'List of cats.' })
  findAll() {
    return [];
  }
}
      

Describing DTOs
Use class-validator and `@ApiProperty()` decorators to describe data transfer objects.

import { ApiProperty } from '@nestjs/swagger';

export class CreateCatDto {
  @ApiProperty({ description: 'Name of the cat' })
  name: string;

  @ApiProperty({ description: 'Age of the cat', minimum: 0 })
  age: number;
}
      

Interactive API testing
Swagger UI lets you interactively test your API via a web interface at `/api` (or your configured path).

// After setup, visit
http://localhost:3000/api
      

Compiling for production
Build your app for production with Ahead-of-Time compilation and tree shaking.

npm run build
node dist/main.js
      

NestJS with Docker
Containerize your app using Docker for consistent deployment.

# Dockerfile example
FROM node:18-alpine

WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY dist ./dist

CMD ["node", "dist/main.js"]
      

CI/CD pipelines
Automate build, test, and deployment with tools like GitHub Actions, GitLab CI, Jenkins.

// Example GitHub Actions snippet
name: CI

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Setup Node
        uses: actions/setup-node@v2
        with:
          node-version: '18'
      - run: npm install
      - run: npm run build
      - run: npm test
      - run: npm run deploy
      

Environment-specific configs
Use different `.env` files or config setups for dev, staging, and production.

ConfigModule.forRoot({
  envFilePath: `.env.${process.env.NODE_ENV}`,
});
      

Transport layers (TCP, Redis, NATS, gRPC, RabbitMQ)
NestJS supports multiple transport layers for microservices communication: TCP sockets, Redis, NATS, gRPC, RabbitMQ.

import { Transport, ClientProxyFactory } from '@nestjs/microservices';

const client = ClientProxyFactory.create({
  transport: Transport.TCP,
  options: { host: 'localhost', port: 4000 },
});
      

Message patterns
Microservices communicate via message patterns handled by decorators like `@MessagePattern()`.

import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';

@Controller()
export class MathController {
  @MessagePattern({ cmd: 'sum' })
  accumulate(data: number[]): number {
    return (data || []).reduce((a, b) => a + b);
  }
}
      

Clients and subscribers
Microservices act as clients to send messages and subscribers to listen.

client.send({ cmd: 'sum' }, [1, 2, 3]).subscribe(result => {
  console.log('Sum is', result);
});
      

Microservices architecture patterns
Common patterns: Event-driven, request-response, CQRS, saga. NestJS supports these with built-in abstractions.

Creating monorepo with Nest CLI
Nest CLI supports creating monorepos, which allow multiple projects (apps/libs) in one repository for better code sharing and management.

// Create monorepo
nest new project-name --monorepo
      

Sharing code between apps/libs
You can create libraries inside the monorepo that can be imported by multiple apps, avoiding duplication.

// Generate library
nest generate library common

// Use shared code
import { SharedService } from '@project/common';
      

Managing multiple apps
The monorepo can contain several apps with separate entry points but shared dependencies and tooling.

// Run specific app
npm run start:app1

// Build specific app
npm run build:app2
      

Dynamic modules
Dynamic modules allow you to configure modules at runtime, useful for features like conditional imports or providers.

@Module({})
export class DynamicModule {
  static forRoot(options: any): DynamicModule {
    return {
      module: DynamicModule,
      providers: [{ provide: 'CONFIG_OPTIONS', useValue: options }],
      exports: ['CONFIG_OPTIONS'],
    };
  }
}
      

Lifecycle hooks (OnModuleInit, OnModuleDestroy)
These hooks let you run code when a module initializes or is destroyed, useful for setup or cleanup tasks.

@Injectable()
export class AppService implements OnModuleInit, OnModuleDestroy {
  onModuleInit() {
    console.log('Module initialized');
  }

  onModuleDestroy() {
    console.log('Module destroyed');
  }
}
      

Custom decorators
Create your own decorators to add metadata or modify behavior on classes, methods, or parameters.

export function Roles(...roles: string[]) {
  return SetMetadata('roles', roles);
}

@Roles('admin')
@Controller('admin')
export class AdminController {}
      

Reflection and metadata
Use `Reflect` API to read and write metadata for classes or methods, enabling powerful features like guards or validation.

import 'reflect-metadata';

Reflect.defineMetadata('role', 'admin', AdminController);
const role = Reflect.getMetadata('role', AdminController);
console.log(role); // admin
      

Lazy loading
Load modules or components only when needed to improve startup time and reduce memory usage.

@Module({
  imports: [LazyModule],
})
export class AppModule {}

@NgModule({
  imports: [RouterModule.forChild([{ path: '', component: LazyComponent }])],
})
export class LazyModule {}
      

Caching strategies
Use caching to reduce DB calls or expensive operations. Options include in-memory, Redis, or HTTP caching.

@Injectable()
export class CacheService {
  private cache = new Map();

  get(key: string) {
    return this.cache.get(key);
  }

  set(key: string, value: any) {
    this.cache.set(key, value);
  }
}
      

Efficient DB access
Use optimized queries, indexes, and batch operations to speed up database interactions.

const users = await userRepository.find({
  where: { isActive: true },
  relations: ['profile'],
});
      

Profiling and monitoring
Use tools like APMs (Application Performance Monitors) to track bottlenecks and monitor app health.

// Example with New Relic or similar tools
app.use(newrelicMiddleware());
      

Domain-driven design (DDD)
DDD is an approach to software development that focuses on the core business domain. In NestJS, organize code around domains, encapsulating business logic in domain modules.

// Example folder structure by domain
src/
├── users/
│   ├── domain/
│   │   ├── entities/
│   │   │   └── user.entity.ts
│   │   ├── services/
│   │   │   └── user.service.ts
│   ├── application/
│   │   └── user.use-case.ts
│   ├── infrastructure/
│   │   └── user.repository.ts
│   └── users.module.ts
      

Clean architecture in NestJS
Clean architecture separates concerns into layers: Presentation (Controllers), Application (Use Cases), Domain (Entities/Services), and Infrastructure (Data access).

// Example of layered approach
@Controller('users')
export class UserController {
  constructor(private readonly userUseCase: UserUseCase) {}

  @Get(':id')
  getUser(@Param('id') id: string) {
    return this.userUseCase.execute(id);
  }
}

// Application layer
export class UserUseCase {
  constructor(private readonly userService: UserService) {}

  execute(id: string) {
    return this.userService.findById(id);
  }
}
      

Layered folder structure
Organize folders by responsibility, e.g., `controllers/`, `services/`, `repositories/`, `dtos/`, and `entities/`.

src/
├── users/
│   ├── controllers/
│   │   └── user.controller.ts
│   ├── services/
│   │   └── user.service.ts
│   ├── repositories/
│   │   └── user.repository.ts
│   ├── dtos/
│   │   └── create-user.dto.ts
│   └── entities/
│       └── user.entity.ts
      

Best practices for scaling
- Keep modules small and focused.
- Use feature modules.
- Apply dependency inversion and SOLID principles.
- Use shared modules for common services.
- Use CQRS and Event Sourcing if necessary.

// Example shared module
@Module({
  providers: [LoggerService],
  exports: [LoggerService],
})
export class SharedModule {}