Skip to content
Putting technology to work.
Insights to guide decisions and action.

Search articles

Full ESM migration in NestJS v12: steps for modernizing existing enterprise client backends in 2026

Table of contents · 7 items

NestJS published "NestJS v12 Roadmap: Full ESM Migration, Standard Schema Validation and Modernised Toolchain" on April 30, 2026. The primary change is the full migration from CommonJS to ESM, accompanied by support for Standard Schema to uniformly handle libraries like Zod and Valibot, as well as a toolchain overhaul transitioning from Webpack to Vite and Rolldown.

NestJS is widely adopted in Japan as an API server framework for enterprise systems and SaaS platforms, and we maintain it for multiple clients. Codebases built on CommonJS have accumulated over several years, making v12 a major update that definitively requires migration work. This article outlines how to handle the migration to NestJS v12 in custom development, from auditing tasks to planning a phased rollout.

Why a "full ESM migration" matters right now

Dual maintenance of ESM (ECMAScript Modules) and CommonJS has been a chronic source of friction across the Node.js ecosystem since the early 2020s. Entering 2026, major libraries have begun switching exclusively to ESM, and remaining on CommonJS increasingly leads to situations where "the latest versions cannot be used."

Benefits of ESM migrationImpact on custom development projects
Improved tree-shaking efficacyBundle size reduced by 20–40%, shortened Lambda cold starts
Top-level await becomes availableSynchronous startup configuration routines become easier to write
Ability to adopt the latest librariesEnables direct use of node-fetch v3.x, chalk v5.x, and similar releases
Vite- and Rolldown-based buildsDevelopment server startup is 5 to 10 times faster

The downside of inaction is also clear: the biggest risk is that "libraries missing security patches will accumulate." This coincides with the major language-level transition covered in the TypeScript 6 Migration Guide, and tackling both at once ultimately proves to be more cost-effective.

Overview of tasks required for the NestJS v12 migration

Here is an audit of tasks in a typical enterprise NestJS project, detailing what needs to be modified.

Work areaDetailsEstimated effort (medium-sized project)
Migrating package.json to "type": "module"Entry points and extensions0.5 person-days
Updating module and moduleResolution in tsconfig.jsonUpgrading to NodeNext and Bundler lines0.5 person-days
Adding .js extensions to relative importsModifying all import statements1 to 3 person-days (automatable)
Replacing __dirname and __filenameMigrating to a import.meta.url base0.5 person-days
Rewriting dynamic require callsMigrating to a import() base1 to 2 person-days
Checking decorator and DI compatibilityNestJS metadata generation behavior1 to 3 person-days
Migrating validators to Standard Schemaclass-validator → Zod, etc.2 to 5 person-days
Updating build, Docker, and CIMigrating to Vite base1 to 3 person-days
Testing (Jest / Vitest) adaptationSwitching to ESM mode2 to 5 person-days
Verification and performance benchmarkingAll endpoints3 to 5 person-days

In total, expect approximately 5 to 10 person-days for small projects, 15 to 30 person-days for medium projects, and 30 to 60 person-days for large projects.

Phased migration approach — avoiding an "all-at-once v12 upgrade"

Because upgrading major versions all at once dramatically increases failure rates, we recommend a two-phase migration.

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 へ
  └─ テスト・本番リリース → 性能比較レポート

By designing the process so that stopping after Phase A still delivers tangible value, issues with library compatibility can be resolved even if Phase B is delayed due to budget constraints. This follows the phased migration mindset outlined in Migrating from Prisma to Drizzle ORM and Migrating to AWS App Runner: in custom development, designs where value is locked in even if the migration pauses midway are exceedingly resilient.

Tasks that can and cannot be automated

Here is an evaluation of automation feasibility to ensure accurate effort estimation.

TaskAutomationTool
Adding .js to relative imports✅ Possiblets-add-js-extension / Codemod
Replacing __dirname✅ PossibleCustom jscodeshift
Updating tsconfig.json✅ PossibleManual + verify with linting
Decorator behavior changes❌ ManualRefer to the official NestJS migration guide
Migrating validators to schema△ Semi-automatedGenerate initial drafts with LLMs, review by humans
ESM adaptation for tests△ Semi-automatedjest.config for extensionsToTreatAsEsm

Semi-automation leveraging LLMs is particularly effective for validator migrations, where converting class-validator DTOs into Zod schemas is well within the capabilities of Claude and GPT. However, because generated outputs may not be type-equivalent, comprehensive coverage through integration tests on every endpoint is mandatory.

Implementation sample — minimal diff for Phase A

Here are the representative diffs required in 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();

With this minimal set of changes, you can reach a state where "the ESM build passes and production runs successfully."

Pitfalls and workarounds

PitfallSymptomMeasure
Third-party DI lacks ESM supportDI fails to resolve at startupBump to an ESM-compatible version or build an in-house wrapper
Stumbling blocks around Worker, Bull, or RabbitMQQueue workers fail to bootAdopt a dual configuration running only the worker side on CJS
Jest mock behavior changesTest spies fail to attachConsider migrating to Vitest simultaneously
TypeORM and Prisma behaviorEntity auto-discovery breaksResolve paths using absolute paths
Docker image bloatChanges in bundling format lead to duplicate copyingClean up output: 'standalone' artifacts

Worker and Bull components are particularly prone to issues; keeping the option to leave worker processes on CJS during Phase A significantly lowers migration risk.

Summary — Turning "ESM migration" into a milestone for client maintenance

The full ESM migration in NestJS v12 represents one of the largest major updates of 2026 for enterprise backend systems. Neglecting it halts dependency updates and drives up CVE remediation costs, making it wise to explicitly place this "inevitable task" onto the roadmap.

In migrating from NestJS v11 to v12, both the required timeline and staffing depend on the balance between what can be handled mechanically with Codemods (adding .js to relative imports, replacing __dirname) and what requires human judgment (decorator behavior changes, migrating validators to Standard Schema). Factors such as whether Worker or Bull setups are present, or whether tests remain on Jest, also alter where to draw the boundary for Phase A. Therefore, we design our approach after reviewing your current tsconfig and dependency tree. If you are looking to "upgrade an API server built with TypeScript and NestJS to the latest version" or are "facing challenges with CVE mitigation due to outdated libraries," please reach out via our inquiry form.

Share this articleXFacebook
Kakeru Suzuki

Fascinated by the possibilities of technology, has had a deep interest in programming and digital art since student days

Turn this article's theme into your company's next step

Concrete steps forward for your organization.

We organize your desired architecture, legacy systems, and operational requirements to formulate your next steps toward execution.

  • Desired architecture
  • Integration with existing environments
  • Operational requirements
Consult on development & operations initiatives

You can consult with us from the initial conceptual stage. Details from this article will be carried over to the inquiry form.

Receive the latest articles by email