NestJS 11: Todas las novedades del framework backend de Node.js

NestJS 11: Todas las novedades del framework backend de Node.js

NestJS 11 trae mejoras significativas en logging, microservicios, rendimiento y soporte para Express v5. Descubre todas las nuevas características.

6 min de lectura

NestJS 11 fue lanzado en enero de 2025, trayendo mejoras significativas orientadas a mejorar la experiencia del desarrollador y el rendimiento de las aplicaciones. En este artículo exploraremos todas las novedades de esta versión.

Logger Mejorado con Soporte JSON

El ConsoleLogger recibió una actualización importante con mejor formateo para objetos anidados, arrays, Maps y Sets. La característica más destacada es el soporte nativo para logging en formato JSON.

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    logger: {
      json: true,
      colors: process.env.NODE_ENV === 'development',
    },
  });
  await app.listen(3000);
}
bootstrap();

Beneficios del JSON Logging

  • Integración con herramientas de agregación como ELK Stack, Datadog o CloudWatch
  • Parsing automatizado en entornos containerizados
  • Búsqueda estructurada de logs en producción
  • Compatibilidad con sistemas de monitoreo modernos

Mejoras en Microservicios

NestJS 11 introduce tres nuevos métodos poderosos para trabajar con microservicios:

Método unwrap()

Permite acceso directo a la instancia del cliente subyacente para operaciones personalizadas:

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

@Injectable()
export class NotificationService {
  constructor(private readonly client: ClientProxy) {}

  async getUnderlyingClient() {
    // Acceso directo al cliente NATS, Kafka, Redis, etc.
    const natsClient = this.client.unwrap();

    // Ahora puedes usar métodos nativos del cliente
    return natsClient;
  }
}

Método on() para Eventos

Escucha eventos internos como desconexiones para reaccionar en tiempo real:

@Injectable()
export class ConnectionMonitor implements OnModuleInit {
  constructor(private readonly client: ClientProxy) {}

  onModuleInit() {
    this.client.on('disconnect', () => {
      console.log('Conexión perdida con el broker');
      // Lógica de reconexión o alertas
    });

    this.client.on('reconnect', () => {
      console.log('Reconectado al broker');
    });
  }
}

Observable status

Proporciona actualizaciones dinámicas del estado de conexión:

@Injectable()
export class HealthService {
  constructor(private readonly client: ClientProxy) {}

  getConnectionStatus() {
    return this.client.status.pipe(
      map(status => ({
        connected: status === 'connected',
        status,
        timestamp: new Date(),
      }))
    );
  }
}

Los estados disponibles son:

  • connecting - Intentando conectar
  • connected - Conexión establecida
  • disconnected - Desconectado
  • reconnecting - Intentando reconectar

Optimización de Rendimiento en el Arranque

NestJS 11 reemplazó las funciones hash por referencias de objetos para generar claves opacas de módulos dinámicos. Esto mejora significativamente los tiempos de arranque en aplicaciones con muchos módulos dinámicos.

// Antes: El framework usaba hash functions (más lento)
// Ahora: Usa referencias de objetos (más rápido)

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    TypeOrmModule.forRootAsync({
      useFactory: (config: ConfigService) => ({
        type: 'postgres',
        host: config.get('DB_HOST'),
        // ... más configuración
      }),
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}

Nota: Este cambio trata módulos con configuración idéntica como instancias separadas en lugar de fusionarlos.

Nuevo ParseDatePipe

Un nuevo pipe para facilitar el trabajo con fechas:

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

@Controller('events')
export class EventsController {
  @Get()
  findByDate(
    @Query('startDate', ParseDatePipe) startDate: Date,
    @Query('endDate', ParseDatePipe) endDate: Date,
  ) {
    return this.eventsService.findBetweenDates(startDate, endDate);
  }
}

IntrinsicException

Nueva clase de excepción que omite el logging automático del framework:

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

@Injectable()
export class AuthService {
  async validateToken(token: string) {
    if (!token) {
      // Esta excepción NO será logueada automáticamente
      throw new IntrinsicException('Token inválido');
    }
    // ...
  }
}

Útil para:

  • Errores sensibles que no deben aparecer en logs
  • Validaciones donde el logging es innecesario
  • Control granular sobre qué se registra

Mejoras en CQRS

El paquete @nestjs/cqrs ahora soporta:

Providers con Request Scope

@CommandHandler(CreateUserCommand)
@Injectable({ scope: Scope.REQUEST })
export class CreateUserHandler implements ICommandHandler<CreateUserCommand> {
  constructor(
    private readonly request: Request, // Acceso al request actual
  ) {}

  async execute(command: CreateUserCommand) {
    // Lógica con acceso al contexto del request
  }
}

Commands, Events y Queries Tipados

// Comando fuertemente tipado
export class CreateUserCommand implements ICommand {
  constructor(
    public readonly email: string,
    public readonly name: string,
  ) {}
}

// Query fuertemente tipada
export class GetUserQuery implements IQuery {
  constructor(public readonly id: string) {}
}

// El handler infiere los tipos correctamente
@QueryHandler(GetUserQuery)
export class GetUserHandler implements IQueryHandler<GetUserQuery, User> {
  async execute(query: GetUserQuery): Promise<User> {
    // query.id tiene tipo string
    return this.userRepository.findOne(query.id);
  }
}

Cambios en ConfigService

El ConfigService ahora lee valores en un orden diferente, permitiendo sobrescribir valores de process.env:

// config/app.config.ts
export default () => ({
  port: 3000, // Este valor tiene prioridad sobre process.env.PORT
  database: {
    host: 'localhost',
  },
});

// Nuevo: opción skipProcessEnv
@Module({
  imports: [
    ConfigModule.forRoot({
      skipProcessEnv: true, // Ignora process.env completamente
      load: [appConfig],
    }),
  ],
})
export class AppModule {}

Soporte para Express v5 y Fastify v5

NestJS 11 actualiza las dependencias a las últimas versiones de Express y Fastify.

Migración de Express v5

La sintaxis de rutas wildcard cambió:

// Antes (Express v4)
@Get('/*')
findAll() {}

// Después (Express v5)
@Get('/*splat')
findAll() {}

// Caracteres opcionales
// Antes
@Get('/users/:id?')

// Después
@Get('/users{/:id}')

Cómo Actualizar

Para actualizar tu proyecto a NestJS 11:

# Actualizar dependencias core
npm install @nestjs/common@11 @nestjs/core@11 @nestjs/platform-express@11

# O con yarn
yarn add @nestjs/common@11 @nestjs/core@11 @nestjs/platform-express@11

# O con pnpm
pnpm add @nestjs/common@11 @nestjs/core@11 @nestjs/platform-express@11

Checklist de Migración

  1. Actualizar sintaxis de rutas wildcard si usas Express
  2. Revisar módulos dinámicos que dependían de la fusión automática
  3. Actualizar configuración del logger si necesitas JSON
  4. Revisar uso de ConfigService si dependías del orden anterior

Conclusión

NestJS 11 representa una evolución importante del framework, con mejoras enfocadas en:

  • Observabilidad: Logger JSON nativo para mejor integración con herramientas de monitoreo
  • Microservicios: Mayor control y flexibilidad con unwrap(), on() y status
  • Rendimiento: Arranque más rápido con la nueva generación de claves
  • DX: Nuevos pipes, excepciones y mejoras en tipado

Si estás iniciando un nuevo proyecto, NestJS 11 es la mejor opción. Para proyectos existentes, la migración es relativamente sencilla, especialmente si no usas Express v5 wildcards.


Fuentes: