NestJS が 2026 年 4 月 30 日に 「NestJS v12 Roadmap: Full ESM Migration, Standard Schema Validation and Modernised Toolchain」 を公開しました。最大の変更は CommonJS から ESM への完全移行で、加えて Zod / Valibot などを統一的に扱える Standard Schema への対応、Webpack から Vite / Rolldown 系へのツールチェーン刷新が入ります。
NestJS は日本でも業務システムや SaaS の API サーバーとして広く採用されており、弊社でも複数のクライアントで運用しています。CommonJS 前提で書かれたコードベースは数年蓄積されており、v12 はメジャーアップデートとして確実に作業が発生する移行です。本記事では、NestJS v12 への移行を受託でどう進めるか、価格レンジを含めて整理します。
なぜ「ESM 完全移行」が今、効いてくるのか
ESM(ECMAScript Modules)と CommonJS の二重運用は、2020 年代前半から続く Node.js エコシステムの 慢性的な混乱でした。2026 年に入り、主要ライブラリが ESM 専用に切り替わり始め、CommonJS のままだと 「最新版が使えない」 局面が増えています。
| ESM 化の効果 | 受託案件への影響 |
|---|---|
| Tree-shaking が効きやすくなる | バンドルサイズ -20〜40%、Lambda コールドスタート短縮 |
| Top-level await が使える | 起動時設定の同期処理が書きやすくなる |
| 最新ライブラリへ追従できる | node-fetch v3 系、chalk v5 系などがそのまま使える |
| Vite / Rolldown ベースのビルド | 開発サーバの起動が 5〜10 倍速 |
放置するデメリットも明確で、「セキュリティパッチが当たらないライブラリが累積」するのが最大のリスクです。これは TypeScript 6 移行ガイド で扱った言語側のメジャー移行と並走するタイミングで、両方を一度に片付けるのが結果として安く済みます。
NestJS v12 移行で発生する作業の全体像
具体的にどこを直す必要があるか、典型的な業務系 NestJS プロジェクトでの作業棚卸しです。
| 作業領域 | 内容 | 工数目安(中規模プロジェクト) |
|---|---|---|
package.json の "type": "module" 化 | エントリポイント / 拡張子 | 0.5 人日 |
tsconfig.json の module / moduleResolution 更新 | NodeNext / Bundler 系へ | 0.5 人日 |
相対 import に .js 拡張子付与 | 全 import 文を修正 | 1〜3 人日(自動化可) |
__dirname / __filename の置換 | import.meta.url ベースに | 0.5 人日 |
| 動的 require の書き換え | import() ベースに | 1〜2 人日 |
| デコレータ / DI の互換確認 | NestJS のメタデータ生成挙動 | 1〜3 人日 |
| Validator の Standard Schema 化 | class-validator → Zod 等 | 2〜5 人日 |
| ビルド / Docker / CI 更新 | Vite ベースへ | 1〜3 人日 |
| テスト(Jest / Vitest)対応 | ESM モード切替 | 2〜5 人日 |
| 動作確認 / 性能比較 | 全エンドポイント | 3〜5 人日 |
合計で 小規模 5〜10 人日、中規模 15〜30 人日、大規模 30〜60 人日程度が目安です。
段階的移行アプローチ — 「一括 v12」を避ける
メジャーバージョンを一度に上げると事故率が跳ね上がるため、弊社では 2 段階移行を提案します。
Phase A(v11 系のまま ESM 化)— 4〜6 週間
├─ "type": "module" + .js 拡張子付与
├─ __dirname 置換
├─ ライブラリの ESM 対応版へ更新
└─ テスト・本番リリース → 1〜2 週間運用観察
Phase B(v11 → v12 への移行)— 4〜6 週間
├─ NestJS v12 へ依存更新
├─ Standard Schema 対応
├─ ツールチェーン Vite/Rolldown へ
└─ テスト・本番リリース → 性能比較レポート
Phase A だけで一旦止めても価値が出る設計にしておくと、予算の関係で Phase B が後ろ倒しになっても、ライブラリ追従の課題は解消できます。これは Drizzle ORM への Prisma 移行 や AWS App Runner 移行 で書いた “段階的移行” の考え方と同じで、移行の途中で止まっても価値が確定する設計が受託では強いです。
自動化できる作業・できない作業
工数の見積を正確にするための、自動化可否の整理です。
| 作業 | 自動化 | ツール |
|---|---|---|
相対 import に .js 付与 | ✅ 可能 | ts-add-js-extension / Codemod |
__dirname 置換 | ✅ 可能 | jscodeshift カスタム |
tsconfig.json 更新 | ✅ 可能 | 手動 + lint で検証 |
| デコレータの挙動変化 | ❌ 手動 | NestJS 公式マイグレーションガイド参照 |
| Validator の Schema 移行 | △ 半自動 | LLM で初稿生成、人がレビュー |
| テストの ESM 対応 | △ 半自動 | jest.config の extensionsToTreatAsEsm |
LLM を活用した半自動化は、特に Validator 移行で効果が大きく、class-validator の DTO を Zod スキーマに変換するのは Claude / GPT に任せられる範囲です。ただし 生成結果は型レベルで等価でない可能性があるため、エンドポイントごとの統合テストでカバレッジを取るのが必須です。
実装サンプル — Phase A の最小差分
Phase A で必要な代表的な差分です。
// package.json
{
"type": "module",
"main": "dist/main.js",
"scripts": {
"build": "nest build",
"start": "node --enable-source-maps dist/main.js"
}
}
// tsconfig.json
{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
"target": "ES2022",
"esModuleInterop": true
}
}
// src/utils/path.ts — __dirname の代替
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
export const __filename = fileURLToPath(import.meta.url);
export const __dirname = dirname(__filename);
// src/main.ts — 相対 import に .js 拡張子
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module.js'; // 拡張子必須
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();
この最小差分で 「ESM ビルドが通り、本番が動く」 状態に持っていけます。
価格レンジ — 受託パッケージ
弊社で NestJS v12 移行を受託するときの価格レンジです。
| 規模 | 行数目安 | Phase A 期間 / 費用 | Phase B 期間 / 費用 |
|---|---|---|---|
| 小規模 | 〜30k LOC | 4 週 / 250〜400 万円 | 4 週 / 250〜400 万円 |
| 中規模 | 30k〜100k LOC | 6 週 / 450〜700 万円 | 6 週 / 500〜800 万円 |
| 大規模 | 100k+ LOC | 10 週 / 900〜1,500 万円 | 10 週 / 1,000〜1,800 万円 |
ポイントは 「Phase A だけでも単独で発注できる」設計にすること。発注側の予算サイクルで分割発注しやすく、案件成約率が明らかに上がります。さらに 移行完了後の保守を月額 30〜80 万円で巻き取ると、追加リリースや CVE 対応もまとめて引き受けられます。
落とし穴と対策
| 落とし穴 | 症状 | 対策 |
|---|---|---|
| サードパーティ DI が ESM 非対応 | 起動時に DI が解決できない | ESM 互換版にバンプ、なければ自前ラッパー |
| Worker / Bull / RabbitMQ 系で躓く | キューワーカーが起動しない | Worker 側だけ CJS で動かす二重構成 |
| Jest のモック挙動変化 | テストの spy が刺さらない | Vitest 移行を同時に検討 |
| TypeORM / Prisma 系の挙動 | エンティティ自動検出が壊れる | パス解決を絶対パス化 |
| Docker イメージ肥大化 | バンドル形態が変わり多重コピー | output: 'standalone' 系の整理 |
特に Worker / Bull 系はハマりやすく、Phase A の段階で ワーカー部分は CJS のまま残す選択肢を持っておくと、移行リスクを大きく下げられます。
まとめ ─ 「ESM 化」を受託保守の節目に
NestJS v12 の ESM 完全移行は、業務システムバックエンドにとって 2026 年最大級のメジャーアップデートです。放置すると依存ライブラリの更新が止まり、CVE 対応コストが膨らむため、「いつかやらないといけない」作業を明示的にロードマップに乗せるのが得策です。
弊社では、NestJS v11 → v12 への移行(ESM 化 + Standard Schema 対応)を、Phase A / Phase B の 2 段階パッケージで提供しています。「TypeScript / NestJS で構築した API サーバーを最新版に追従させたい」「ライブラリが古いまま残っており、CVE 対応で困っている」というご相談は お問い合わせフォーム からお気軽にどうぞ。