# How to Implement Custom Exception Filters in NestJS: A Complete Guide

> Learn to implement custom exception filters in NestJS. Create a class, use @Catch decorator, and handle errors effectively for better application management.

- Repository: [nestjs/nest](https://github.com/nestjs/nest)
- Tags: how-to-guide
- Published: 2026-03-01

---

**To implement custom exception filters in NestJS, create a class implementing the `ExceptionFilter` interface, decorate it with `@Catch()` to specify target exception types, and implement the `catch(exception, host)` method to process errors and format responses.**

Exception filters in NestJS provide a centralized mechanism for handling thrown errors across HTTP, WebSocket, and RPC contexts. According to the nestjs/nest source code, the framework treats these filters as first-class citizens with deep integration into the IoC container and metadata reflection systems. Mastering how to implement custom exception filters allows you to standardize error responses, log failures consistently, and keep business logic clean.

## Understanding the ExceptionFilter Interface

Every custom filter must honor the contract defined in [`packages/common/interfaces/exceptions/exception-filter.interface.ts`](https://github.com/nestjs/nest/blob/main/packages/common/interfaces/exceptions/exception-filter.interface.ts). This interface mandates a single method:

```typescript
catch(exception: T, host: ArgumentsHost): any

```

The `T` generic represents the exception type your filter handles, while `ArgumentsHost` provides a unified abstraction to access the underlying execution context. This design enables the same filter logic to work across HTTP, WebSockets, and microservice transports without modification.

## How NestJS Processes Exception Filters

### Metadata Reflection via @Catch

The `@Catch(...exceptions)` decorator attaches metadata to your filter class using the internal `FILTER_CATCH_EXCEPTIONS` key. When the application initializes, `BaseExceptionFilterContext.reflectCatchExceptions` reads this metadata to determine which exception types trigger your filter. This reflection logic resides in [`packages/core/exceptions/base-exception-filter-context.ts`](https://github.com/nestjs/nest/blob/main/packages/core/exceptions/base-exception-filter-context.ts).

### The Filter Resolution Flow

When an error bubbles up to the router, Nest resolves applicable filters through the `ExceptionFiltersContext`—a subclass of `BaseExceptionFilterContext` that handles concrete filter instantiation. The context performs four critical operations:

1. Resolves the filter instance from the IoC container
2. Extracts the `catch` function reference
3. Matches the thrown exception against registered types stored in `FILTER_CATCH_EXCEPTIONS` metadata
4. Invokes `filter.catch(exception, host)` for each matching filter

The `host` parameter exposes platform-specific methods: `switchToHttp()`, `switchToWs()`, and `switchToRpc()`, enabling transport-agnostic error handling.

## Creating a Custom Exception Filter

Follow this implementation pattern derived from [`sample/36-hmr-esm/src/common/filters/http-exception.filter.ts`](https://github.com/nestjs/nest/blob/main/sample/36-hmr-esm/src/common/filters/http-exception.filter.ts) to handle HTTP exceptions:

```typescript
import {
  ArgumentsHost,
  Catch,
  ExceptionFilter,
  HttpException,
} from '@nestjs/common';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter<HttpException> {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();

    const status = exception.getStatus();

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url,
    });
  }
}

```

The `@Catch(HttpException)` decorator restricts this filter to `HttpException` and its subclasses. The `ArgumentsHost` abstraction allows access to the underlying Express or Fastify response objects through `switchToHttp()`.

## Registering Exception Filters

### Global Registration

Apply filters across your entire application using `useGlobalFilters()`, implemented in the `INestApplication` interface:

```typescript
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './common/filters/http-exception.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(new HttpExceptionFilter());
  await app.listen(3000);
}
bootstrap();

```

### Controller-Level Registration

Scope filters to specific controllers or routes using the `@UseFilters()` decorator:

```typescript
import { Controller, Get, UseFilters } from '@nestjs/common';
import { HttpExceptionFilter } from './common/filters/http-exception.filter';

@Controller('cats')
@UseFilters(HttpExceptionFilter)
export class CatsController {
  @Get()
  findAll() {
    // Exceptions here pass through HttpExceptionFilter
  }
}

```

### Catch-All Exception Filters

Create a universal error handler by passing no arguments to `@Catch()`:

```typescript
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    
    const status = exception instanceof HttpException
      ? exception.getStatus()
      : 500;

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: ctx.getRequest().url,
    });
  }
}

```

## Summary

- **ExceptionFilter interface**: Mandates a `catch(exception, host)` method defined in [`packages/common/interfaces/exceptions/exception-filter.interface.ts`](https://github.com/nestjs/nest/blob/main/packages/common/interfaces/exceptions/exception-filter.interface.ts)
- **Metadata reflection**: `@Catch()` stores exception types using the `FILTER_CATCH_EXCEPTIONS` key, read by `BaseExceptionFilterContext.reflectCatchExceptions` in [`packages/core/exceptions/base-exception-filter-context.ts`](https://github.com/nestjs/nest/blob/main/packages/core/exceptions/base-exception-filter-context.ts)
- **Registration options**: Use `app.useGlobalFilters()` for application-wide handling or `@UseFilters()` for controller-scoped filtering
- **Cross-platform support**: `ArgumentsHost` provides `switchToHttp()`, `switchToWs()`, and `switchToRpc()` for transport-agnostic error handling
- **Filter resolution**: `BaseExceptionFilterContext` orchestrates filter instantiation and execution, while `RouterExceptionFilters` handles the router-level collection

## Frequently Asked Questions

### What is the ExceptionFilter interface in NestJS?

The `ExceptionFilter` interface defines the contract that all exception filters must implement. Located in [`packages/common/interfaces/exceptions/exception-filter.interface.ts`](https://github.com/nestjs/nest/blob/main/packages/common/interfaces/exceptions/exception-filter.interface.ts), it requires a single `catch(exception: T, host: ArgumentsHost)` method where you implement error handling logic and response formatting.

### How do I make an exception filter catch all exceptions?

Apply the `@Catch()` decorator without arguments to your filter class. This registers the filter for every thrown exception, not just specific types. NestJS stores this configuration using the `FILTER_CATCH_EXCEPTIONS` metadata key and processes it through `BaseExceptionFilterContext.reflectCatchExceptions`.

### Can I use exception filters with WebSockets or microservices?

Yes. The `ArgumentsHost` parameter provides transport-agnostic access through `switchToWs()` for WebSockets and `switchToRpc()` for microservices. The same filter infrastructure in [`packages/core/exceptions/base-exception-filter-context.ts`](https://github.com/nestjs/nest/blob/main/packages/core/exceptions/base-exception-filter-context.ts) supports all platforms, with specialized handlers like `RpcExceptionsHandler` extending the base functionality.

### What is the difference between @UseFilters and useGlobalFilters?

`@UseFilters()` applies filters to specific controllers or methods via decorator metadata, processed during route registration. `useGlobalFilters()` registers filters on the `INestApplication` instance, applying them to every route in the application. Global filters are resolved once during bootstrap, while controller-level filters follow the standard dependency injection lifecycle.