In any real-world backend application, proper error handling is essential. It ensures that your system doesn't crash unexpectedly, responds clearly to clients, and makes debugging easier for developers. Luckily, NestJS provides powerful tools to do this cleanly and professionally.
Let’s explore how to handle errors effectively in NestJS using built-in exceptions, global filters, and custom strategies.
🚨 Why is Error Handling Important?
Errors happen: invalid input, missing resources, database failures, unreachable services… A backend that doesn't handle these gracefully will:
- Crash or hang
- Leak sensitive data
- Return unclear or inconsistent responses
NestJS allows us to build resilient APIs that fail smart, not hard.
✅ Level 1: HTTP Exceptions (Built-in)
NestJS offers ready-to-use exception classes like BadRequestException, NotFoundException, UnauthorizedException, etc.
Example:
@Get(':id')
async findOne(@Param('id') id: string) {
const user = await this.userService.findById(id);
if (!user) {
throw new NotFoundException(`User with ID ${id} not found`);
}
return user;
}
👉 Nest will automatically respond with a 404 and a structured JSON response.
🧱 Level 2: Global Exception Filter
For centralized error handling, you can create a custom exception filter to catch and format all uncaught exceptions globally.
Example:
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
Logger,
} from '@nestjs/common';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
private readonly logger = new Logger(AllExceptionsFilter.name);
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const status = exception instanceof HttpException
? exception.getStatus()
: 500;
const message = exception instanceof HttpException
? exception.getResponse()
: 'Internal server error';
this.logger.error('Exception caught', exception instanceof Error ? exception.stack : '');
response.status(status).json({
statusCode: status,
message,
timestamp: new Date().toISOString(),
});
}
}
Enable it globally:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './common/filters/all-exceptions.filter';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalFilters(new AllExceptionsFilter());
await app.listen(3000);
}
bootstrap();
🔁 Now all unhandled errors are caught and returned with a unified format.
🎯 Level 3: Custom Exceptions
You can define your own domain-specific exceptions for business logic clarity.
import { BadRequestException } from '@nestjs/common';
export class DuplicatedEmailException extends BadRequestException {
constructor(email: string) {
super(`The email ${email} is already registered`);
}
}
Use it like:
if (userExists) {
throw new DuplicatedEmailException(email);
}
🧪 Level 4: Automatic Validation Errors with class-validator
When using DTOs with class-validator and ValidationPipe, NestJS handles validation errors out of the box.
@IsEmail()
email: string;
@MinLength(6)
password: string;
Enable it globally in main.ts:
app.useGlobalPipes(new ValidationPipe());
🔐 This will respond with 400 Bad Request if the input doesn't meet the defined constraints.
🧵 Bonus: Error Handling in Microservices
If you're using NestJS with Kafka, RabbitMQ, or other transport layers, use RpcException inside your message handlers:
@MessagePattern('create-user')
async createUser(data: CreateUserDto) {
try {
return await this.userService.create(data);
} catch (error) {
throw new RpcException('Error creating user');
}
}
This prevents crashes and enables proper retry or dead-letter strategies in your messaging system.
🧠 Final Thoughts
Error handling in NestJS is not just about catching bugs—it's about building services that:
- Are user-friendly (clear responses)
- Are developer-friendly (structured logs and debugging)
- Follow clean architecture and domain logic boundaries
By combining exception filters, DTO validation, and custom errors, you’ll write APIs that are robust, scalable, and production-ready.
Top comments (0)