@maru

NestJS 12プレビュー — class-validatorを捨ててZodを直接使う
NestJS 12プレビューは、バックエンド開発を煩雑にしていたレガシーな依存関係と複雑なビルド設定を大幅に改善するメジャーアップデートです。コアレベルでStandard Schema 1.0をサポートし、class-validatorなしでもZodやValibotでリクエストデータを直接検証できるようになり、パッケージ全体がネイティブESMに移行します。さらに、RspackやVitestといったRustベースの高性能ツールチェーンをデフォルトで導入し、開発生産性も大幅に向上しました。バックエンド開発者の視点から、今回のメジャーアップデートがどのような課題を解決し、安全に移行するために何を準備すべきかを一つずつ解説します。
Standard Schema 1.0の導入:class-validatorとの決別
NestJS 12の最大の変更点の一つは、Standard Schema 1.0規格をフレームワークのコアにネイティブで導入したことです。これからはルートハンドラの@Body()、@Query()、@Param()デコレータに、ZodやValibotなどのスキーマを引数として直接渡せるようになります。
以前のNestJSでペイロードを検証するにはclass-validatorとclass-transformerに依存する必要がありました。この方式はデコレータベースで動的に型を推論するため、tsconfig.jsonにおいてemitDecoratorMetadataオプションを必ず有効にする必要がありました。しかし、このオプションはTypeScriptのコンパイル時に重い計算を要求するだけでなく、Rspack、Vite、esbuildのようなRustベースの超高速バンドラーと互換性がなく、モダンなビルドツールを導入する上での最大の障壁となっていました。
NestJS 12はこの問題を解決するために、組み込みのStandardSchemaValidationPipeを提供します。実行時にメタデータのリフレクションに依存せず、デコレータに直接注入されたスキーマオブジェクトの標準検証メソッドをパイプ内部で直接実行する構造です。おかげで、面倒なコンパイラオプションの設定やランタイムリフレクションのオーバーヘッドなしに、安全で高速な検証パイプラインを構築できます。
従来のclass-validator方式と、NestJS 12のZodベース検証方式を比較するとその違いは明らかです。
// [기존 방식] class-validator 사용 (emitDecoratorMetadata 옵션 필수)
import { IsString, IsEmail } from 'class-validator';
export class CreateUserDto {
@IsString()
name!: string;
@IsEmail()
email!: string;
}
@Post()
create(@Body() createUserDto: CreateUserDto) {}// [NestJS 12 방식] Standard Schema 사용 (Zod 스키마 직접 주입)
import { z } from 'zod';
export const CreateUserSchema = z.object({
name: z.string(),
email: z.string().email(),
});
@Post()
create(@Body({ schema: CreateUserSchema }) body: z.infer<typeof CreateUserSchema>) {}このようにスキーマをコントローラデコレータに直接渡すだけで、内部的にStandardSchemaValidationPipeがペイロードを検証し、必要に応じてStandardSchemaSerializerInterceptorがレスポンスのシリアライズまで処理します。複雑な外部統合ライブラリなしで標準スキーマ仕様をそのまま使えるため、開発者体験とビルド速度の両方が大幅に向上します。
ネイティブESMへの移行と同期式require(esm)互換性
NestJS 12のすべてのコアパッケージはネイティブESMに移行します。これまでバックエンドエコシステムにおいて、CommonJSとESM間のモジュールインポート設定は、開発者の時間を最も奪う慢性的な問題でした。今回のメジャーアップデートでは、この壁を壊すために最新のNode.js環境における同期的なrequire(esm)機能を積極的に活用します。
同期式require(esm)はNode.js v20.19.0以上およびv22.12.0以上で公式サポートされる核心機能です。この機能のおかげで、既存のCommonJSベースで作成されたレガシーアプリケーション設定をすぐに完全に変更しなくても、ネイティブESMでビルドされたNestJS 12コアパッケージを安全に読み込んで互換性を維持できます。
実際のコミュニティのベンチマーク結果を見ても、NestJS 11ベースのCJS環境とNestJS 12ネイティブESM環境の間でのコールドスタート時間や、アイドル時のメモリ占有率(RSS)の差はほとんどありません。結局、今回のESM移行の真の価値は、目先の劇的なパフォーマンス向上よりも、現代的なESM専用ライブラリを複雑な設定や特別なラッパーなしで即座にプロジェクトへ統合できる開発体験の改善にあります。
Rspack、Vitest、oxlintを包含する超高速Rustツールチェーン
NestJS 12は開発のフィードバックループを劇的に短縮するため、Rustベースの現代的な開発ツールを大幅に採用しました。この新しいビルドおよびテストシステムは、CLIコマンドで作成する新規ネイティブESMプロジェクトテンプレートにデフォルトで適用されます。既存のCommonJSプロジェクトとのエコシステムの安定性を考慮し、CJSベースのテンプレートは既存のWebpack、Jest、ESLint構成をそのまま維持します。
最初に目につく変化は、長年デフォルトバンドラーとして活躍したWebpackが、Rustベースの超高速バンドラーであるRspackに置き換わったことです。ビルド性能が数倍以上速くなり、ローカル開発サーバーの起動とプロダクションビルドの速度が劇的に改善されます。さらに、コード分析ツールも重いESLintの代わりに、Rustで記述され圧倒的なパース速度を誇るoxlintを採用することで、保存時のコード分析待ち時間を最小化しました。
テスト環境にも大きな変化があります。ESM環境で設定が面倒で重かったJestの代わりに、Vitestが新しいデフォルトのテストランナーとして導入されます。特にこのVitestは、超高速構文解析エンジンであるOXCを搭載しており、NestJSの複雑なデコレータを迅速に処理します。実際の移行事例によると、以前は42秒かかっていたテスト全体の実行時間が11秒にまで短縮されるなど、開発者がローカルやCI/CDパイプラインで感じる待ち時間が圧倒的に削減されます。
安全な移行のために今準備すべきこと
NestJS 12への移行を安定的に進めるには、ランタイム環境とTypeScript設定を事前に調整しておく必要があります。
まずサーバーが動作するNode.jsのバージョンをアップデートする必要があります。コアパッケージがネイティブESMに移行しても、既存のCommonJSプロジェクトとの互換性を崩さないためには、同期的なrequire(esm)機能を正式にサポートするNode.js v20.19.0以上、またはv22.12.0以上の環境を確保しなければなりません。
次の段階として、TypeScriptコンパイラの設定を変更します。tsconfig.jsonファイルでmoduleとmoduleResolutionオプションを両方NodeNextに更新し、ESMモジュールの探索ルールを明確に定義する必要があります。
{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext"
}
}NodeNext規格を適用すると、ローカルファイルを相対パスで取得するすべてのimport構文に.js拡張子を必須で明記する必要があります。実際の開発ソースファイルが.ts拡張子で記述されていても、ビルド後に実行されるJavaScriptの結果物を基準にパスが解釈されるため、事前にインポート構文をすべて確認し、拡張子を追加しておくことを推奨します。
結論:移行を今すぐ適用すべきか
NestJS 12はフレームワークの足を引っ張っていた古い技術的負債を整理し、エコシステムの現代化を牽引する重要なアップデートです。新しく始めるプロジェクトであるか、あるいはすでにZodやESMパッケージを積極的に使用しているなら導入する価値は十分にあります。Rustベースの新しい開発ツールチェーンとネイティブESMの利便性を即座に享受できるからです。
ただし、既存サービスを運用中なら急ぐ必要はありません。実際のベンチマーク結果によると、ESMへの移行がもたらす劇的なランタイムパフォーマンス向上やメモリ削減効果は微々たるものです。したがって、パフォーマンス改善を目的として無理にアップグレードを断行するのではなく、class-validatorベースのコードを段階的に標準スキーマに移行し、使用中のライブラリのESMサポート状況を確認しながら慎重に進めるのが賢明な移行戦略です。
参考リンク