La NestJS 12 fue lanzada oficialmente el 27 de agosto de 2026 y es una de las actualizaciones más profundas de la historia del framework — pero, curiosamente, una de las que menos exige reescritura de código de aplicación.
La versión gira en torno a cuatro frentes: paquetes ESM, soporte de primera clase a Standard Schema para validación y serialización, una CLI reconstruida desde cero y observabilidad nativa a través del nuevo paquete @nestjs/observe.
Y hay un punto importante desde el principio: las aplicaciones CommonJS siguen funcionando. Migrar su propio código a ESM es totalmente opcional.
Entre los destacados están:
- Todos los paquetes del core ahora son ESM, con CommonJS continuando a funcionar a través de
require(esm); - Standard Schema en los decoradores de ruta, permitiendo Zod, Valibot y ArkType en
@Body(),@Query()y@Param(); - Serialización por esquema con el nuevo
StandardSchemaSerializerInterceptor; - Observabilidad nativa con el SDK
@nestjs/observe; - CLI reconstruida, con los nuevos comandos
nest upgradeynest deploy; - Rspack en lugar de webpack, oxlint en lugar de ESLint y Vitest como estándar en proyectos ESM;
- Diagnóstico de conflicto de rutas, para identificar rutas sombreadas o duplicadas;
- Códigos de error legibles por máquina en las excepciones HTTP;
- Logs estructurados por defecto en el
ConsoleLogger; - Node.js v20.19+ o v22.12+ como requisito mínimo.
Vamos a entender lo que cambia en la práctica.
Los paquetes de NestJS ahora son ESM
El cambio arquitectónico más importante de NestJS 12 es la migración de los paquetes del core de CommonJS a ESM.
Esta discusión ya venía arrastrándose en el ecosistema Node.js durante años, y el motivo por el cual finalmente se desbloqueó es técnico: el soporte a require(esm) en las versiones modernas de Node.js.
En la práctica, esto significa que un proyecto CommonJS puede seguir cargando paquetes que son ESM, sin necesitar reescribir imports, convertir archivos o cambiar la estrategia de build.
Por eso la recomendación oficial es directa: en la mayoría de los proyectos, no es necesario hacer nada.
Aun así, vale la pena revisar tres puntos que suelen asumir CommonJS de forma implícita:
- Scripts personalizados de bootstrap de la aplicación;
- Herramientas y configuraciones de construcción;
- Test runners y mocks que dependen del formato de los módulos.
También es un buen momento para eliminar deep imports — esos imports que alcanzan rutas internas de los paquetes de Nest en lugar de usar la API pública. Siempre han sido frágiles, y siguen siendo el tipo de cosa que se rompe al cambiar el formato de módulo.
Otro cambio visible está en la creación de proyectos. El comando:
nest new
ahora pregunta si quiere generar un proyecto CommonJS o ESM. La elección también define el resto de la toolchain, como veremos más adelante.
Validación con Standard Schema directamente en los decoradores
Si sigues el ecosistema TypeScript, probablemente ya te hayas encontrado con el Standard Schema: una especificación común que las bibliotecas de validación implementan para poder ser usadas de forma intercambiable.
NestJS 12 adopta esta especificación de forma nativa.
Los decoradores de parámetro de ruta — @Body(), @Query(), @Param() y @RawBody() — aceptan una nueva opción schema, pensada para bibliotecas compatibles como Zod, Valibot y ArkType:
@Post()
create(@Body({ schema: createUserSchema }) body: CreateUserDto) {
return this.usersService.create(body);
}
@Get(':id')
findOne(@Param('id', { schema: z.coerce.number().int().positive() }) id: number) {
return this.usersService.findOne(id);
}
Hay un detalle de implementación que vale la pena entender bien: el decorador solo anexa el metadato. No valida nada por sí solo.
Quien valida es el nuevo pipe, que necesita ser registrado:
app.useGlobalPipes(new StandardSchemaValidationPipe());
Esto mantiene la arquitectura del framework coherente con lo que ya existía: el decorador describe la intención, el pipe ejecuta.
Una ganancia importante es que los mismos esquemas alimentan la generación de OpenAPI. Es decir, no necesitas mantener una definición para validar y otra para documentar.
Y, para quienes ya tienen una base grande escrita en el modelo tradicional, el mensaje es tranquilizador: el flujo con class-validator sigue totalmente soportado, sin ningún plan de eliminación.
La serialización también ganó una versión Standard Schema
La misma idea fue llevada al camino de salida de la solicitud.
El nuevo StandardSchemaSerializerInterceptor valida y transforma la respuesta utilizando el mismo ecosistema de esquemas:
@UseInterceptors(StandardSchemaSerializerInterceptor)
@SerializeOptions({ schema: userResponseSchema })
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(id);
}
Esto resuelve un problema bastante concreto de APIs en producción: garantizar que el objeto devuelto al cliente contenga exactamente los campos previstos — y no aquello que accidentalmente vino de la base de datos.
La elección entre los dos enfoques es por caso de uso:
- ValidationPipe y ClassSerializerInterceptor para DTOs basados en clases;
- Versiones Standard Schema cuando los esquemas ya existen en el proyecto.
Observabilidad nativa con @nestjs/observe
Quizás la novedad más estratégica de NestJS 12 sea el @nestjs/observe, el SDK oficial de observabilidad del framework.
La diferencia en relación a un APM genérico está en el enfoque. En lugar de instrumentar el servidor HTTP por fuera, el SDK se conecta al propio ciclo de vida de la solicitud de Nest, a través de una nueva opción de la aplicación llamada instrument:
export const { ObserveModule, ObserveInstrument } = createObserveModule();
const app = await NestFactory.create(AppModule, {
instrument: ObserveInstrument,
});
La consecuencia práctica es que los datos llegan descritos en los términos de su aplicación: controllers, providers, resolvers y consumidores de cola — y no en términos de rutas HTTP genéricas.
La instrumentación automática cubre:
- HTTP;
- GraphQL;
- gRPC;
- Transportes de microservicios;
- Consumidores de cola;
- Ejecutores de cron.
Sin instrumentación manual de spans y sin necesidad de ejecutar un collector.
Es un recurso opt-in y nuevo, es decir: no hay nada que migrar. Tanto el nest new como el nest upgrade pueden hacer la configuración inicial con la opción --observe.
El @nestjs/config ahora valida por Standard Schema
El módulo de configuración dejó de estar acoplado a Joi.
La opción validationSchema ahora acepta cualquier esquema compatible con Standard Schema:
ConfigModule.forRoot({
validationSchema: z.object({
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
PORT: z.coerce.number().default(3000),
}),
});
Quien ya usa Joi no necesita reescribir nada, pero debe observar dos puntos:
- Actualizar a Joi v18+, que es la primera versión en implementar Standard Schema;
- Mover las configuraciones específicas de la biblioteca a
validationOptions.libraryOptions.
Diagnóstico de conflicto de rutas
Este es el tipo de recurso que solo tiene sentido para quienes ya han perdido tiempo con el problema.
Las rutas de Nest se registran en el orden de declaración. En adaptadores sensibles al orden, esto significa que una ruta como:
@Get(':id')
puede silenciosamente sombrear una ruta declarada después:
@Get('me')
El resultado es una solicitud a /users/me que llega al handler de /users/:id con el id valiendo la cadena "me". Ningún error, ninguna advertencia — solo un comportamiento incorrecto.
NestJS 12 trae dos opciones opt-in para exponer este escenario:
const app = await NestFactory.create(AppModule, {
routeConflictPolicy: { duplicate: 'error', shadow: 'warn' },
routeResolutionStrategy: 'specificity',
});
Ambas mantienen el comportamiento anterior por defecto, así que nada cambia a menos que las configures explícitamente.
Códigos de error legibles por máquina
Otra mejora pequeña en tamaño y grande en impacto del día a día.
Las HttpExceptionOptions pasan a aceptar un errorCode, que se serializa en el cuerpo de la respuesta:
throw new BadRequestException('Password is too weak', { errorCode: 'WEAK_PASSWORD' });
Con esto, el cliente puede ramificar la lógica sobre un identificador estable, en lugar de hacer comparación de cadena en el mensaje de error — que cambia cuando alguien corrige una coma o traduce el texto.
Logs estructurados en ConsoleLogger
El ConsoleLogger ahora trata a los objetos pasados después del mensaje como parámetros estructurados del mismo registro, y no como registros separados:
logger.log('User created', { userId: 1, email: '[email protected]' });
En modo JSON, estos datos quedan anidados bajo params, o pueden ser esparcidos en la raíz con flattenParams.
El comportamiento viene activado por defecto. Para volver al formato anterior, basta configurar structuredParams: false.
La CLI de NestJS fue reconstruida
La @nestjs/cli v12 no solo recibió comandos nuevos: fue reescrita.
El código fuente completo migró a ESM, las pruebas salieron de Jest a Vitest, se agregaron pruebas end-to-end para todos los comandos, y las clases de comando pasaron a recibir objetos de contexto tipados en lugar de entradas y arreglos de opciones sin tipo.
Nuevos comandos
nest upgrade(aliasupdate) — actualiza un proyecto v11 a v12 y aplica los pasos mecánicos de la migración;nest deploy— publica la aplicación en la nube a través de Mau, instalando el@nestjs/mauen el primer uso.
Nuevos estándares de toolchain
- Rspack pasa a ser el bundler estándar para monorepos. Las flags
--webpacky--webpackPath(y sus equivalentes ennest-cli.json) están depreciadas a favor de--builder rspack; - oxlint reemplaza a ESLint en los proyectos generados;
- Vitest es el test runner estándar en proyectos ESM; los proyectos CommonJS continúan con Jest;
- bun pasa a ser un gestor de paquetes soportado, junto a npm, yarn y pnpm;
- El schematic
decoratorahora genera decorators en el formato preferidoReflector.createDecorator(), y el schematicangularha sido eliminado.
Nuevas opciones
nest buildynest start:--rspackPath [path],--emit-declarations(SWC),--no-type-checky--silent;nest build:--parallel [concurrency], para compilar proyectos de un monorepo en paralelo junto con--all;nest-cli.json:includeLibraryAssets, para copiar assets de libraries al build de la aplicación.
Novedades repartidas por el resto del framework
Además de las principales novedades, NestJS 12 trae una serie de mejoras menores que resuelven molestias muy específicas:
- Formato de error del ValidationPipe — una nueva opción controla el formato de las respuestas de error de validación;
- Filtro de excepción para gRPC — el
GrpcExceptionFiltery excepciones específicas por estado mapean errores a los estados correctos del gRPC, en lugar de devolverUNKNOWN; - Padrões Kafka por expressão regular —
@MessagePattern()y@EventPattern()aceptan unRegExpen el transporte Kafka; - Gateways WebSocket con escopo de requisição — los gateways pasan a soportar providers request-scoped, con el socket inyectable por el token
REQUEST; - Motivo del disconnect — el
handleDisconnectpuede recibir el motivo de la desconexión; - Hook pre-solicitud en microservicios — un nuevo hook se ejecuta antes de que se invoque el handler del mensaje;
- Apagado gracioso en Express — el adaptador drena las solicitudes en curso al apagarse;
- Mapeo de errores de los adaptadores HTTP — retrabajado en el core, en Express y en Fastify.
El apagado gracioso de Express, en particular, es una de esas correcciones que quienes ejecutan Kubernetes agradecen: durante un rollout, las solicitudes en curso dejan de ser interrumpidas a la mitad.
Qué se rompe al subir a NestJS 12
El equipo optó por concentrar los cambios incompatibles fuera del código de aplicación. Aun así, vale la pena conocer la lista:
- Node.js v20.19+ o v22.12+ — la línea 21.x no es soportada, y el comando de upgrade se niega a ejecutarse en versiones anteriores;
- Paquetes en ESM — normalmente nada cambia, gracias al
require(esm); revisa bootstrap, bundler y test runner personalizados; - Hooks de ciclo de vida — ahora son invocados por nivel de jerarquía de los componentes; revisa supuestos de orden entre providers y módulos relacionados;
- NATS v3 — el paquete
natsfue sustituido por@nats-io/transport-node; los mensajes pasan a ser serializados como JSON y deserializadores personalizados reciben el mensaje completo, leído conmsg.json(); - Suscripciones a GraphQL — el soporte a
subscriptions-transport-wsha sido eliminado a favor degraphql-ws; los protocolos son incompatibles a lo largo del hilo, así que los clientes necesitan ser actualizados; - GraphiQL pasa a ser la IDE estándar de GraphQL — cambia
playgroundporgraphiql; - @nestjs/config — validación a través de Standard Schema, con Joi v18+ y
validationOptions.libraryOptions; - Firmas de pipes — refinadas, con
ArgumentMetadataahora genérico; ajusta pipes personalizados si el compilador reclama; - ConsoleLogger con parámetros estructurados activado por defecto;
- Flujos con webpack en la CLI depreciados, a favor de
--builder rspack; - Schematic
angulareliminado.
La buena noticia es que la mayor parte de esto se trata automáticamente por el nest upgrade.
Cómo actualizar a NestJS 12
El primer paso es actualizar la CLI, ya que es ella la que carga el comando de upgrade:
npm i -g @nestjs/cli@latest
Luego, desde la raíz del proyecto:
nest upgrade
El comando mueve todos los paquetes @nestjs/* a la major compatible con la v12 de una vez y aplica las partes mecánicas de la migración:
- Opciones de webpack en
nest-cli.json; - Renombramiento de
playgroundagraphiqlen GraphQL y cambio del transporte de suscripciones; - Sustitución del paquete de NATS;
- Opciones de validación del
@nestjs/config; - Actualizaciones de Jest y Joi.
Al final, imprime un informe con todo lo que cambió y todo lo que aún necesita revisión manual.
Antes de aplicar en un proyecto real, vale la pena ejecutar:
nest upgrade --dry-run
para ver ese mismo informe sin que se toque ningún archivo.
Y un punto importante: el comando deliberadamente no migra su proyecto a ESM, Vitest o oxlint. Estos son los estándares de proyectos nuevos — los proyectos existentes adoptan a su propio ritmo.
Como en cualquier actualización de major, la hoja de ruta segura sigue siendo la misma:
- Ejecutar toda la suite de pruebas automatizadas;
- Validar autenticación, guards, interceptors y pipes personalizados;
- Comprobar microservicios, colas y trabajos programados;
- Probar el proceso de build y el despliegue en un ambiente de staging antes de la producción.
¿Vale la pena actualizar a NestJS 12?
Para proyectos que ya están en NestJS 11, la actualización es mucho menos arriesgada de lo que sugiere el número de la major — precisamente porque los cambios más radicales ocurren en capas que la aplicación normalmente no toca.
Lo que se gana solo por subir de versión:
- Apagado gracioso en Express;
- Mapeo correcto de errores en los adaptadores HTTP;
- Estados adecuados en las excepciones de gRPC;
- Logs estructurados en el
ConsoleLogger.
Lo que es adopción opcional, y puede entrar después con calma:
- Migrar el proyecto a ESM;
- Cambiar class-validator por Zod, Valibot o ArkType;
- Adoptar Vitest, oxlint y Rspack;
- Activar el
@nestjs/observe.
El principal bloqueo práctico no es el framework, sino el runtime: si su entorno aún ejecuta una versión de Node.js anterior a v20.19, esa es la primera cosa a resolver.
¿Qué muestra NestJS 12 sobre la dirección del framework?
Al observar el conjunto, NestJS 12 tiene una línea bastante clara.
Por un lado, el framework se está alineando al ecosistema en lugar de mantener soluciones propias: ESM en lugar de CommonJS, Standard Schema en lugar de acoplamiento a una biblioteca de validación específica, graphql-ws en lugar de un transporte legado.
Por otro lado, está modernizando la toolchain con implementaciones nativas de alto rendimiento — Rspack y oxlint siguen exactamente la misma tendencia que representa Turbopack en el mundo de Next.js.
Y hay un tercer frente, más silencioso: varias novedades de esta versión existen para hacer el comportamiento del sistema observable. Conflictos de rutas que dejan de ser invisibles. Códigos de error que el cliente puede interpretar. Logs que se convierten en datos estructurados. Observabilidad que habla el lenguaje de sus controllers.
Son mejoras menos vistosas que una nueva API, pero que atacan justamente el tipo de problema que suele costar caro en producción.
Preguntas frecuentes sobre NestJS 12
¿Cuándo se lanzó NestJS 12?
NestJS 12.0.0 fue lanzado oficialmente el 27 de agosto de 2026.
¿Qué hay de nuevo en NestJS 12?
Las principales novedades son los paquetes en ESM, el soporte de primera clase a Standard Schema para validación y serialización, la CLI reconstruida con los comandos nest upgrade y nest deploy, y la observabilidad nativa a través del SDK @nestjs/observe.
¿Necesito migrar mi aplicación a ESM en NestJS 12?
No. Los paquetes de Nest pasaron a ser ESM, pero las aplicaciones CommonJS siguen funcionando gracias al require(esm) de las versiones modernas de Node.js. Migrar su propio código es opcional.
¿Cuál es la versión mínima de Node.js para NestJS 12?
Es necesario Node.js v20.19+ o v22.12+. La línea 21.x no es soportada, y el comando nest upgrade se niega a ejecutarse en versiones anteriores. Se recomienda usar la LTS activa más reciente.
¿Se eliminará el class-validator de NestJS?
No. El soporte a Standard Schema es una alternativa, no una sustitución. El flujo basado en decoradores con class-validator sigue totalmente soportado, sin plan de eliminación.
¿Cómo actualizar un proyecto de NestJS 11 a 12?
Actualiza la CLI con npm i -g @nestjs/cli@latest y ejecuta nest upgrade en la raíz del proyecto. Ejecuta primero con --dry-run para ver el informe de lo que se cambiaría sin tocar los archivos.
¿NestJS 12 obliga a usar Vitest y oxlint?
No. Vitest, oxlint y ESM son los estándares solo para proyectos nuevos generados por la CLI. El nest upgrade no convierte proyectos existentes a ellos.
¿Qué es el @nestjs/observe?
Es el SDK oficial de observabilidad de NestJS. Se conecta al ciclo de vida de la solicitud del propio framework a través de la opción instrument, y instrumenta automáticamente HTTP, GraphQL, gRPC, transportes de microservicios, consumidores de cola y ejecuciones de cron — sin instrumentación manual de spans y sin collector.