NestJS 12 Ships: ESM, Standard Schema, Observability
On August 27, 2026 Kamil Myśliwiec published NestJS v12.0.0. The major that
had been tracking "approximately Q3 2026" under the next tag is now stable, and
it lands almost exactly as scoped: every official package ships as ESM, Standard
Schema validation and serialization are built into the framework, the CLI has been
rebuilt, and there is a first-party observability SDK. There is also a nest upgrade
command that does most of the migration for you.
If you read our NestJS 12 roadmap post in June, the shape is familiar. What changed between the draft PR and the release is mostly in the details — and the details are where the upgrade work lives.
ESM, and the Node floor that comes with it
All core packages are now ECMAScript modules. Existing CommonJS applications keep
working through require(esm), so migrating your own source to ESM stays optional.
What is not optional is the runtime: v12 requires Node.js v20.19+ or v22.12+, and
the 21.x line is not supported. Check your Dockerfiles and CI images before anything
else — that is the constraint most likely to stop the upgrade cold.
The parts that need a real look are custom bootstrapping and build configuration.
If you have hand-rolled Webpack config, a custom main.ts entry, or anything that
reaches into Nest's internals through require, budget time for it.
Standard Schema, in both directions
Route parameter decorators — @Body(), @Query(), @Param() and @RawBody() —
now accept a schema option that takes any Standard Schema-compatible
object, which means Zod, Valibot and ArkType are first-class without a wrapper
library. The one thing the roadmap post could not tell you: you have to register the
new StandardSchemaValidationPipe for it to do anything.
The genuinely new half is serialization. StandardSchemaSerializerInterceptor
validates outgoing responses against the same schemas:
@SerializeOptions({ schema: userResponseSchema })
@Get(':id')
findOne(@Param('id') id: string) {
return this.users.findOne(id);
}
That closes the gap class-transformer never quite covered — a response shape you
can assert on rather than hope for. @nestjs/config moves the same way: it drops
Joi-specific validation for Standard Schema, so validationSchema accepts any
compatible schema. If you are staying on Joi, it must be v18 or later.
@nestjs/observe
The new observability SDK plugs into Nest's own request lifecycle through the
instrument application option rather than monkey-patching the HTTP server the way
a generic APM agent does. It covers HTTP, GraphQL, gRPC, microservices, queues and
cron jobs without per-handler instrumentation.
The distinction matters in practice: an agent that patches the server sees a request and a response, while something wired into the lifecycle can attribute time to a guard, an interceptor or a specific provider. For anyone who has tried to work out why p99 moved on a Nest API, that is the difference between a number and an answer.
The CLI, and the toolchain that actually shipped
@nestjs/cli v12 adds nest upgrade to migrate v11 projects, and nest deploy
for Mau. Rspack is the new default bundler for monorepos; the --webpack and
--webpackPath flags are deprecated in favour of --builder rspack. oxlint replaces
ESLint, and bun joins the supported package managers.
One correction to what we wrote in June: Vitest is the default only for ESM projects. CommonJS projects continue with Jest. If you take the ESM path and Jest you will be on your own.
Breaking changes worth checking first
Beyond ESM and the Node floor, the migration table calls out several that will bite specific stacks:
- NATS:
npm uninstall nats && npm install @nats-io/transport-node, then update imports - GraphQL:
subscriptions-transport-wssupport is removed — migrate tographql-ws; GraphiQL is now the default IDE, so replaceplaygroundwithgraphiql - Lifecycle hooks now run by hierarchy level, so review provider and module ordering
ConsoleLoggertreats plain objects after a message as structured params; setstructuredParams: falseto keep the old behaviour- The angular schematic has been removed
What to do now
Nothing urgent. This is a major with real breaking changes, not a security patch, and 11.x is still getting work — 11.2.2 and 11.2.3 both landed on August 25 with bug fixes. Staying on 11 through the next sprint is a defensible call.
When you do move, start with the runtime. Get onto Node 20.19+ or 22.12+ first, as its own change, then:
npm i -g @nestjs/cli@latest
nest upgrade --dry-run
--dry-run prints the changes without applying them, which makes it a cheap way to
size the job before committing to it. Read that diff against the list above — the
codemod handles the mechanical parts, not your NATS transport or your GraphQL
subscription layer.
Full details are in the v12.0.0 release notes and the original scope PR #16391.
Sitting on a Nest 11 codebase with custom Webpack config and a NATS transport, and unsure what the upgrade actually costs? Talk to us.