Node.js 25: what’s actually new, what broke in the ecosystem, and whether you should upgrade
A real-world review of Node.js 25 (Current): V8 14.1 and performance, Web Storage enabled by default (breaking tests/tools), the permission model with --allow-net, portable module compile cache (now stable), require(esm) marked stable, http.setGlobalProxyFromEnv(), fs.watch got ignore, and SEA can be built in one step with node --build-sea. Developer perspectives with links + a clear verdict: upgrade now or wait for LTS.

There are two kinds of Node upgrades. The first is “bump the version, everything works.” The second is “bump the version, and now your backend throws browser-looking errors.” Node.js 25 made a lot of teams experience the second kind.
Docusaurus looked surreal: DOMException [SecurityError]: Cannot initialize local storage without a --localstorage-file path during docusaurus build.[1] Similar symptoms showed up in the CLI world (Shopify) and in test runners (Jest/Vitest).[2][3][4]
This matters: it’s not just “a random bug in your repo.” It’s a consequence of Node 25 enabling Web Storage by default, while Node’s localStorage is not a 1:1 browser storage (file-backed, quota, shared behavior, no encryption).[7][5]
And still: it would be a mistake to reduce Node 25 to the Web Storage saga. 25.4.0 and 25.5.0 shipped genuinely mature improvements (require(esm) stable, compile cache stable, --build-sea) that reduce migration pain and improve DX — if you adopt them deliberately.[9][10][12]
A real case: docusaurus build fails on Node 25.x due to a localStorage SecurityError.[1]
Node 25 is a Current line (odd). It moves fast: first, new defaults land; then the ecosystem finds edge cases; then stabilization releases ship.[6]
• 25.0.0: V8 14.1, performance focus, web APIs, permission model, Web Storage enabled by default.[8]
• 25.2.0: the
localStorageregression without--localstorage-filesurfaces (nodejs/node #60704) and impacts toolchains.[5]• 25.4.0: require(esm) becomes stable, module compile cache becomes stable, ops goodies like
http.setGlobalProxyFromEnv()land.[9]• 25.5.0:
node --build-seaarrives — SEA “one step from core”, plus small but meaningful ops/monorepo changes.[12]
Just enough vocabulary to make Node 25 readable.
• Current vs LTS: odd major = Current, even major = LTS line. Node explicitly recommends production use Active/Maintenance LTS.[6]
• Web Storage in Node: Node
localStorageis file-backed (--localstorage-file), unencrypted, has a 10MB quota, and is shared within a server process.[7]• Permission Model: process permissions (
--permission,--allow-net,--allow-fs-read) as a seatbelt. It’s not a sandbox and provides no guarantees against malicious code.[11]• require(esm): a bridge between CJS and ESM. Node 25.4.0 marks the mechanism stable (which changes migration strategy).[9]
• Module compile cache: on-disk code cache for speeding up module graph compilation, with a
portablemode.[10]• SEA: single executable applications. 25.5.0 makes this much easier with
--build-sea.[12][13]• Ops QoL: proxy from env (
http.setGlobalProxyFromEnv()), watcher ignore (fs.watch({ ignore: ... })).[14][15]
25.0.0 is the foundation: V8 14.1, performance work, web APIs, and legacy cleanup. The real “maturity” shows up in 25.4/25.5.[8][9][12]
14.1
The 25.0.0 notes highlight performance improvements, including JSON.stringify.[8]
enabled by default
A bold default change that triggered ecosystem regressions (tools/tests/CLIs).[8][5][4]
permissions
Permissions are framed as “secure-by-default”, with clear constraints (not a sandbox).[11]
deprecations
Major releases often hurt via deprecated API removal (SlowBuffer is a good example).[16]
A visual marker of the line start: Node.js 25.0.0 (Current).[8]
Section node-25-0 screenshotThe core issue is not that Web Storage is “bad”. The issue is that the default behavior changed, and parts of toolchains started executing branches they never tested on the server.
nodejs/node #60704 describes the 25.2.0 regression: “Cannot initialize local storage without a --localstorage-file path”. Importantly, it references broken webpack/jest/html-webpack-plugin chains.[5]
Vitest issue #8757 shows another failure mode: in Node 25 localStorage is no longer undefined, which can break mocks in test environments.[4] Jest issue #15888 adds another data point: the test runner fails with the same SecurityError on Node 25.2.0.[3]
Fast incident workaround (when you don’t need storage): temporarily disable Web Storage via the flag documented in Node’s globals docs.[7]
Team lesson: even if “you don’t use localStorage”, your dependencies might. That’s why keeping Current in a CI matrix is a rational way to detect surprises early.[6]
nodejs/node #60704: Node 25.2.0 regression — touching localStorage without --localstorage-file can crash builds.[5]
Vitest #8757: Web Storage enabled by default in Node v25 can break tests due to changed localStorage expectations.[4]
Jest #15888: the runner fails with SecurityError on Node 25.2.0.[3]
This is the kind of change that doesn’t scream in headlines, but saves weeks in repos where CJS and ESM must coexist.
1) Why it matters
2) Practical pattern: default export adapter
const pkg = require('some-esm-only-package');
const api = pkg?.default ?? pkg;
module.exports = api;This isn’t a “hack”. It’s a standard way to handle the namespace object when ESM provides a default export.[22]
3) What it signals for teams
Stabilization in Current is preparation for the broader ecosystem. Keeping LTS+Current in CI lets you capture benefits without taking prod risk.[6]
A visual marker of a “stabilization” point: Node.js 25.4.0 (Current).[9]
Section require-esm screenshotCompile cache is an optimization. It shines when you have many cold starts or a large module graph (tools, CLIs, workers).
The node:module docs include a very practical portability section: if absolute paths change, cache effectiveness can drop; portable mode helps reuse in more scenarios.[10]
A minimal experiment setup:
import module from 'node:module';
module.enableCompileCache({ directory: '.node-compile-cache', portable: true });If you test this in CI, manage the cache directory explicitly so it survives between runs.
Docs: “Portability of the compile cache” + portable mode with API and env examples.[10]
This is one of the most product-level changes in the line: building a single executable no longer looks like an external-injector ritual.
1) The core idea
2) Practical takeaway
For CLIs and local agents: fewer dependencies and fewer brittle release steps. But test on target OS/shells (there are reports about Windows Command Prompt quirks).[21]
3) Team advice
SEA is a distribution tool, not a security model. Don’t use it as a substitute for dependency updates and supply-chain hygiene. Keep Current in CI to catch surprises early.[6]
25.5.0: the --build-sea section and the command example in the official release notes.[12]
Not headline features — but they reduce “tiny custom wrappers” in projects with corporate CI constraints.
Minimal snippet:
import http from 'node:http';
const restore = http.setGlobalProxyFromEnv();
// restore();http.setGlobalProxyFromEnv()
Useful when proxies are configured via env (CI/enterprise networks).[14]
call on startup
Avoid calling it mid-request; do it during bootstrap of a service/CLI.[14]
more consistent
Less chance each HTTP client ends up configured differently.
Docs: http.setGlobalProxyFromEnv([proxyEnv]) + built-in proxy support section.[14]
In large repos, watchers are their own world of pain (node_modules, .git, generated dirs). The docs describe ignore as an option that can take glob/RegExp/function/array.[15]
A minimal example for dev tools:
import { watch } from 'node:fs';
watch('.', {
recursive: true,
ignore: ['**/node_modules/**', '**/.git/**'],
}, () => {});Major Node releases often hurt not via brand-new APIs but via deprecation finalization. SlowBuffer is a clean example.[16]
1) What happened to SlowBuffer
Node’s deprecations docs state SlowBuffer was removed and recommend Buffer.allocUnsafeSlow(size).[16]
2) How it looks “in the wild”
There’s a real case of a backend crashing on Node 25.x due to a dependency chain touching SlowBuffer.prototype.[17]
3) Quick pre-upgrade scan
rg -n "\bSlowBuffer\b" .Then pnpm why / npm ls to identify the legacy dependency chain.
A short “battle-tested” checklist teams actually use.
• 1) Keep prod on LTS, add Node 25 in CI (LTS + Current matrix).[6]
• 2) Run tests with Web Storage disabled to quickly isolate the source:
NODE_OPTIONS="--no-experimental-webstorage".[7]• 3) If it broke, look where it already broke: nodejs/node #60704, Vitest #8757, Jest #15888.[5][4][3]
• 4) If you want 25.4/25.5 features, adopt them first in a separate experiment (CLI/worker), not by flipping prod runtime in one go.[9][12]
• 5) For monorepos, tune watchers:
fs.watch({ ignore })reduces noise and load.[15]• 6) For corporate CI behind proxies, try
http.setGlobalProxyFromEnv()as a simple global approach.[14]
No ideology: Node 25 is great as a “future breakage detector” in CI, and it’s useful for certain products (CLIs/agents). But for production backends, LTS often wins on stability alone.
Mostly wait / stay on LTS
Node recommends production run on Active/Maintenance LTS.[6]
Add it now
Node 25 surfaces dependency regressions (Web Storage) and legacy cleanup (SlowBuffer) without prod incident risk.[5][16]
Upgrade is reasonable
--build-sea (25.5.0) + 25.4.0 maturity are real DX wins. Test on target OS/shells.[12][21]
Current is allowed to bite
Current exists so the ecosystem can adapt. If it breaks your day, keep it in CI and keep prod on LTS.[6]
No. It’s Current (odd major). Node explicitly states production apps should use Active or Maintenance LTS.[6]
Because the default changed. `localStorage` became available without an experimental flag, but Node’s semantics differ (file, 10MB, shared). Tooling assumptions broke.[7][5][4]
Temporarily disable Web Storage via `NODE_OPTIONS="--no-experimental-webstorage"` or a runtime flag. It’s documented in globals and referenced as a workaround in regression threads.[7][5]
Yes, but test on target OS/shells. There’s a Windows Command Prompt specific issue.[21] For config/process details see SEA docs.[13]
Sources in order of appearance (position in list = footnote number [n]).
• Docusaurus issue #11545: build broken on Node 25.2.0 due to localStorage SecurityError
• Shopify community: shopify-cli fails on Node 25.2.0 due to localStorage SecurityError
• Jest issue #15888: Jest fails with localStorage error on Node 25.2.0
• Vitest issue #8757: Node v25 breaks tests with Web Storage API
• Node.js Releases: Current vs LTS policy (production guidance)
• Node.js Globals docs: Web Storage semantics + disable flag
• Node.js 25.0.0 release notes (V8 14.1, Web Storage default, performance highlights)
• Node.js 25.4.0 release notes (require(esm) stable, compile cache stable, ops improvements)
• Node.js node:module docs: module compile cache + portability
• Node.js Permissions docs: seat belt approach (not a sandbox)
• Node.js 25.5.0 release notes (--build-sea, other notable changes)
• Node.js Single Executable Applications docs (--build-sea flow and config)
• Node.js Deprecations docs: SlowBuffer removed + migration note
• twentyhq/twenty issue: crash on Node 25 due to SlowBuffer removal via dependency chain
• nodejs/Release issue #1113: cadence discussion (annual majors / LTS duration)
• nodejs/node issue: --build-sea fails in Windows Command Prompt (shell-specific behavior)
• Joyee Cheung: require(esm) in Node.js — from experiment to stability
• Joyee Cheung: Improving SEA building (why build moved into Node.js core)
The healthiest strategy for most teams: keep prod on LTS, run Node 25 in CI as an early regression detector, and adopt 25.4/25.5 features (require(esm), compile cache, build-sea) first in isolated experiments (CLI/worker). You get the DX upside without “the day localStorage broke the build”.
Related Articles
AI SEO / GEO in 2026: Your Next Customers Aren’t Humans — They’re Agents
Search is shifting from clicks to answers. Bots and AI agents crawl, cite, recommend, and increasingly buy. Learn what AI SEO / GEO means, why classic SEO is no longer enough, and how PAS7 Studio helps brands win visibility in the agentic web.
The most powerful Apple chip yet? M5 Pro and M5 Max are breaking records
A data-backed March 2026 analysis of Apple M5 Pro and M5 Max. We break down why these chips can credibly be called Apple's most powerful pro laptop silicon, how they compare with M4 Pro, M4 Max, M1 Pro, M1 Max, and how they stack up against Intel and AMD laptop rivals.
Artemis II and the Code That Carries Humans to the Moon
This article unpacks NASA's Artemis II mission, launched on April 1, 2026, and explains what it really says about modern engineering: flight software, backup logic, simulation, telemetry, human control, and the careful role AI can play in space systems.
Automatic Tagging & Search for Saved Links
Integrate with GDrive/S3/Notion for automatic tagging and fast search via search APIs
Professional development for your business
We create modern web solutions and bots for businesses. Learn how we can help you achieve your goals.