Engineering Practitioner Brief / 18 May 2026

JavaScript and Node.js Legacy Cost

JavaScript is the loudest ecosystem in software. Build tools change every two years, framework majors land annually, library churn is constant. Most of that change is improvement, but the cumulative cost to a codebase that has not kept pace is high. This page lays out the per-component cost lines that show up in a typical Node legacy audit in 2026.

$15K to $80K

Annual carrying cost

200-dep Node app, dependency-debt vector only

$40K to $200K

Full modernisation

50K-line app, Node 12 to 22 plus build-tool, TS, React majors

The Node Runtime Ladder

Node major LTS versions reach end-of-life on a roughly 30-month cycle. Each LTS is supported for about 18 months as active, then 12 months as maintenance-only. The runtime itself is unusually backward-compatible: most code that ran on Node 12 also runs on Node 22. The cost shows up in transitive dependencies, native modules (node-gyp builds need updated toolchains), and runtime APIs that were deprecated and finally removed.

StepNotable Removals or ChangesHours / 50K LOC
Node 12 to 16Removed legacy http parser, V8 update breaks some native modules15 to 35
Node 16 to 18Fetch in core, undici default agent, OpenSSL 310 to 25
Node 18 to 20Stable test runner, permission model preview6 to 15
Node 20 to 22Native ESM stable, V8 12.x5 to 12
Node 12 to 22 (full)Cumulative35 to 80

The Node 12 to 16 step is the most expensive because of the V8 jump and the OpenSSL 3 baseline that arrives in Node 18. Native modules (better-sqlite3, sharp, bcrypt, node-sass) often need updates to compile cleanly. Pre-built binary distributions (prebuild-install) help when the maintainer publishes them; otherwise the build chain has to compile from source against the new Node ABI.


CommonJS to ESM

The migration from CommonJS to ECMAScript Modules is the largest single source of friction in modern Node legacy work. Node has supported ESM since 12.17 but the interop with CommonJS has edge cases that only surface at runtime. The mechanical migration of import / export syntax is straightforward (jscodeshift recipes exist), but the deeper challenges are runtime: require is synchronous, dynamic import() is asynchronous, and the two reach different points in the module graph.

For an application that runs on Node only (not the browser), the practical advice is to migrate when the tooling actively benefits: top-level await, tree-shaking through build tools that prefer ESM, and direct consumption of ESM-only libraries. For library publishers, the dual-publish pattern (shipping both CJS and ESM bundles via package.json exports field) is still common in 2026 because consumers vary.

Typical cost for a 50K-line Node app: 80 to 200 engineer-hours including dependency upgrades that some libraries demand for their ESM-only releases. The cost is heavily front-loaded into the first few files where the interop surface is dense, then drops sharply for the bulk of the codebase.


Build Tool Migration

The 2020 to 2024 period saw a major shift in JavaScript build tooling. Webpack remains the dominant install base but is slow at scale and complex to configure. Vite (esbuild + Rollup), Rspack (Webpack-compatible Rust rewrite), Bun, and Turbopack are the modern options. Most teams choose Vite for application bundling and esbuild for libraries.

MigrationHours / 50K LOCEffect on Dev Server Cold StartRisk
Webpack to Vite80 to 25010x to 50x fasterLoader gaps for niche file types
Webpack to Rspack40 to 1203x to 10x fasterLower (config compatible)
Babel to SWC15 to 502x to 5x faster CI buildsPlugin coverage gaps
Webpack to Turbopack100 to 30010x to 50x fasterNewer, fewer integrations

The economic case is straightforward: a slow dev server costs every engineer waiting time multiple times per day. If a Webpack cold start takes 45 seconds and Vite takes 2 seconds, and an engineer cold-starts 4 times per day, that is 172 seconds saved per day per engineer, or roughly 12 hours per engineer per year. Across a 10-engineer team that is 120 hours, or $10,200 at $85 per hour. The migration pays back inside a year for most teams.


React Major Version Cost

React releases breaking changes infrequently but meaningfully. Each major requires real code work, even when the official codemods cover most of it.


The JavaScript to TypeScript Migration

Adding type coverage to an untyped JavaScript codebase is one of the higher-yield modernisation projects available in 2026. The cost is real but the maintenance recovery is fast. The recommended pattern is incremental: enable allowJs in TypeScript config, convert files one at a time, start with new code and work outward.

Cost reference points: a basic conversion (rename .js to .ts, add any where types are unknown) is 0.4 to 0.8 engineer-hours per file. A meaningful conversion (no any, strict mode on) is 1.2 to 2.5 engineer-hours per file. For a 200-file codebase, the basic pass is 80 to 160 hours; the strict pass is 240 to 500 hours. Most teams do the basic pass first and tighten over months as files are touched for other reasons.

The recovery: TypeScript catches a measurable percentage of defects at compile time that would otherwise surface at runtime. A 2017 paper from UCSD (To Type or Not to Type, Gao, Bird, and Barr) reported that TypeScript would have prevented 15 percent of public bugs in a sample of JavaScript projects. Even discounting for the upper bound of that finding, the prevention rate is high enough that the migration typically pays back inside 18 months. See test debt cost for the related arithmetic on defect-prevention ROI.

Related Reading


Frequently Asked Questions

What does a Node legacy upgrade cost?

For a 50K-line Node.js application moving from Node 12 to Node 22, typically 40 to 120 engineer-hours. The runtime itself is unusually backward-compatible; most cost is in transitive dependencies, build tooling (Webpack to Vite, Babel to SWC), and TypeScript version bumps.

Is CommonJS to ESM worth doing?

For application code, usually yes (tree-shaking, top-level await, ecosystem direction). For libraries you publish, it depends on your audience; many libraries still ship dual CJS / ESM bundles. The migration is more work than it looks because Node's interop between CJS and ESM has edge cases that only surface at runtime.

Webpack to Vite or Webpack to Rspack?

Vite for most applications (mature, fast dev server, plugin ecosystem). Rspack for projects that want a Webpack-compatible config with native-binary speed. The Webpack-to-Vite migration cost for a 50K-line app is typically 80 to 250 engineer-hours; Webpack-to-Rspack is lower (40 to 120 hours) because Rspack accepts most Webpack configuration verbatim.

How expensive is jQuery to modern framework migration?

Effectively a rewrite. jQuery applications interleave DOM manipulation and business logic without a separate model layer. Moving to React, Vue, or Svelte is closer to greenfield development than to upgrade. Plan 18 to 36 months for a 100K-line jQuery app, similar in magnitude to the Angular.js to Angular migration.

Should I migrate from JavaScript to TypeScript?

Yes for any codebase over about 20K lines that expects to live another two years. The migration cost is real (typically 0.4 to 1.2 engineer-hours per JS file for the basic conversion, plus type-correctness work after) but the maintenance cost recovery is fast. The 2023 State of JS survey showed roughly 80 percent of professional JS developers prefer TypeScript for new code.

What is the cost of staying on an old React version?

Compound. React 17 is in the maintenance window; React 18 brought concurrent rendering; React 19 (2024) made class components legacy. Libraries increasingly assume React 18+ APIs (Suspense, useTransition, automatic batching). Staying on React 16 or 17 in 2026 means writing adapter wrappers for modern libraries, which itself accumulates code-debt.

Updated 2026-04-27