PAS7 Studio
До всіх статей

Node.js 25: що нового насправді, що зламалось в екосистемі, і чи варто оновлюватись

Живий розбір Node.js 25 (Current) з історіями з реального світу: V8 14.1 і перформанс, Web Storage увімкнули за замовчуванням (і це зламало тести/тулзи), permission model з --allow-net, portable compile cache (тепер stable), require(esm) став stable, http.setGlobalProxyFromEnv(), fs.watch отримав ignore, і SEA тепер збирається однією командою через node --build-sea. Думки розробників з лінками + чіткий висновок: апгрейдити чи чекати LTS.

Node.js 25 — зміни, реакції розробників і висновок чи варто оновлюватись

Є два типи апгрейду Node. Перший — «підняли версію, все ок». Другий — «підняли версію, а наш проєкт тепер видає браузерні помилки на бекенді». Node.js 25 багатьом запам’ятався другим типом.

Кейс Docusaurus виглядав максимально сюрреалістично: DOMException [SecurityError]: Cannot initialize local storage without a --localstorage-file path — під час docusaurus build.[1] Аналогічні симптоми ловили і в CLI-світі (Shopify), і в тест-раннерах (Jest/Vitest).[2][3][4]

Це важливо: це не «рандомний баг у вашому репо». Це наслідок того, що Node 25 ввімкнув Web Storage за замовчуванням, а localStorage у Node — це не браузерний storage 1:1 (файл, квота, shared-поведінка, відсутність шифрування).[7][5]

І разом з цим у Node 25 є великий плюс: 25.4.0 і 25.5.0 принесли зрілі фічі (require(esm) stable, compile cache stable, --build-sea), які реально зменшують міграційний біль і покращують DX — але їх треба брати з розумом.[9][10][12]

Реальний кейс: docusaurus build падає на Node 25.x через localStorage SecurityError.[1]

Скріншот секції prologue

Node 25 — це Current-лінія (odd). Вона живе швидко: спершу «включили нові дефолти», потім екосистема знаходить edge-cases, потім виходять стабілізаційні релізи.[6]

  • 25.0.0: V8 14.1, акцент на перформанс, web-API, permission model, включення Web Storage by default.[8]

  • 25.2.0: на поверхню вилізла регресія localStorage без --localstorage-file (nodejs/node #60704), яка зачепила тулінг-ланцюжки.[5]

  • 25.4.0: require(esm) стає stable, module compile cache стає stable, додають ops-плюшки на кшталт http.setGlobalProxyFromEnv().[9]

  • 25.5.0: з’являється node --build-sea — SEA «в один крок» із core, плюс дрібні, але важливі зміни для ops/monorepo.[12]

Мінімум понять, без яких Node 25 читається як набір випадкових флагів і regression-тредів.

  • Current vs LTS: odd major = Current, even major = LTS-лінія. Node прямо рекомендує production тримати на Active/Maintenance LTS.[6]

  • Web Storage у Node: localStorage у Node — файл-базований storage (--localstorage-file), незашифрований, квота 10MB, і в серверному процесі він shared.[7]

  • Permission Model: дозволи процеса (--permission, --allow-net, --allow-fs-read) як «ремінь безпеки». Це не sandbox і не дає гарантій проти malicious code.[11]

  • require(esm): міст між CJS і ESM. Node 25.4.0 зафіксував стабільність механізму (і це впливає на міграції).[9]

  • Module compile cache: on-disk code cache для пришвидшення компіляції модульного графа, з portable режимом.[10]

  • SEA: single executable applications. У 25.5.0 це стало значно простіше через --build-sea.[12][13]

  • Ops QoL: проксі з env (http.setGlobalProxyFromEnv()), ігнор у вотчерах (fs.watch({ ignore: ... })).[14][15]

25.0.0 — це фундамент: V8 14.1, перформансні штуки, web-API, і підчищення legacy. Але справжня “зрілість” лінійки відчувається в 25.4/25.5.[8][9][12]

14.1

Реліз-ноти 25.0.0 підкреслюють перформансні покращення, зокрема на JSON.stringify.[8]

enabled by default

Смілива default-зміна, яка дала хвилю регресій в екосистемі (тулінг/тести/CLI).[8][5][4]

permissions

Permission model у фокусі «secure-by-default» підходу, але з чіткими обмеженнями (не sandbox).[11]

deprecations

Major-релізи часто болять не через фічі, а через прибирання deprecated API (приклад — SlowBuffer).[16]

Візуальний маркер початку лінійки: Node.js 25.0.0 (Current).[8]

Скріншот секції node-25-0

Проблема не в тому, що Web Storage — погана ідея. Проблема в тому, що змінилася default-поведінка, і частина тулінгу/бібліотек почала виконувати гілки коду, які ніколи не тестувалися на сервері.

nodejs/node #60704 прямо описує регресію 25.2.0: «Cannot initialize local storage without a --localstorage-file path». І важливий момент: issue посилається на зламані ланцюжки webpack/jest/html-webpack-plugin.[5]

Vitest issue #8757 показує інший тип поломки: у Node 25 localStorage перестає бути undefined, і це може “збити” моки у тестових середовищах.[4] Jest issue #15888 — ще один доказ, що це не поодинокий кейс: тест-раннер падає з SecurityError на Node 25.2.0.[3]

Швидкий антикризовий workaround (коли storage вам не потрібен) — тимчасово вимкнути web storage флагом, який описаний у docs.[7]

Ключова думка для команд: навіть якщо ви «не використовуєте localStorage», ваші залежності можуть робити це опосередковано. Тому Current-лінію логічно тримати в CI-матриці як ранній детектор таких сюрпризів.[6]

nodejs/node #60704: регресія 25.2.0 — localStorage без --localstorage-file провокує падіння.[5]

Скріншот секції webstorage-saga

Vitest #8757: Node v25 вмикає Web Storage, і тести можуть ламатися через зміну очікувань щодо localStorage.[4]

Скріншот секції webstorage-saga

Jest #15888: тест-раннер падає з SecurityError на Node 25.2.0.[3]

Скріншот секції webstorage-saga

Це той клас змін, який не «кричить» у реліз-нотах, але економить тижні в репозиторіях, де CJS і ESM змушені співіснувати.

1) Чому це важливо

Коли частина екосистеми стає ESM-only, старі CJS-коди регулярно ловлять ERR_REQUIRE_ESM. Якщо міст між цими світами стає зрілішим, команди можуть мігрувати поступово — без «big bang» переписування всього репо за один реліз.[9][22]

2) Практичний патерн: адаптер під default export

JS
const pkg = require('some-esm-only-package');
const api = pkg?.default ?? pkg;

module.exports = api;

Це не “хак”. Це типовий спосіб працювати з namespace-object, коли ESM експортує default.[22]

3) Сигнал для великих команд

Стабілізація в Current-лінії — це підготовка до того, що з часом поведінка стане звичною і для LTS-світу. Тому CI-матриця (LTS+Current) тут — найздоровіший спосіб забрати користь без ризику інцидентів.[6]

Візуальний маркер “стабілізаційного” релізу: Node.js 25.4.0 (Current).[9]

Скріншот секції require-esm

Compile cache — це оптимізація, яка найкраще працює там, де у вас багато холодних стартів або великий модульний граф (особливо інструменти, CLI, воркери).

У доках node:module є дуже практичний розділ про переносимість: якщо змінюються absolute paths, кеш може втратити ефективність; portable режим дозволяє reuse у більшій кількості сценаріїв.[10]

Мінімальний приклад, який зазвичай достатній для експерименту:

JS
import module from 'node:module';

module.enableCompileCache({ directory: '.node-compile-cache', portable: true });

Якщо ви це тестуєте в CI, варто керувати директорією кешу явно (щоб не «випаровувався» між прогонами).

Docs: “Portability of the compile cache” + portable режим і env-приклад.[10]

Скріншот секції compile-cache

Це одна з найбільш «продуктових» змін лінійки: тепер збірка single-executable не виглядає як ритуал з зовнішнім інжектором.

1) Базова ідея

25.5.0 вводить --build-sea і консолідує попередні кроки SEA у single step прямо в Node.js core.[12][13]

BASH
echo 'console.log("Hello")' > hello.js
echo '{ "main": "hello.js", "output": "sea" }' > sea-config.json
node --build-sea sea-config.json
./sea

2) Практичний висновок

Для CLI/локальних агентів це означає менше залежностей і менше “крихких” кроків у release pipeline. Але як і все кросплатформене — тестуйте на цільових OS/шелах (є окремі репорти про Windows Command Prompt нюанси).[21]

3) Порада для команд

SEA — це інструмент дистрибуції, не заміна security-моделі. Не підмінюйте ним оновлення залежностей/перевірку supply chain. І тримайте CI-матрицю, бо саме вона ловить сюрпризи Current-ліній.[6]

Реліз 25.5.0: блок про --build-sea і приклад команд прямо в нотатках релізу.[12]

Скріншот секції sea-build-sea

Це той тип змін, який не потрапляє в заголовки, але реально зменшує кількість «дрібних кастомних обгорток» у проєктах з корпоративним CI.

Мінімальний приклад:

JS
import http from 'node:http';

const restore = http.setGlobalProxyFromEnv();
// restore();

http.setGlobalProxyFromEnv()

Зручно для середовищ, де проксі керується через env (CI/enterprise networks).[14]

викликати на старті

Уникайте виклику “посеред запитів”; робіть це на bootstrap етапі сервісу/CLI.[14]

передбачуваніше

Менше шансів, що кожен HTTP-клієнт буде налаштований по-своєму.

Docs: http.setGlobalProxyFromEnv([proxyEnv]) + секція про built-in proxy support.[14]

Скріншот секції ops-qol

Якщо у вас великий репозиторій, вотчери — це окремий світ болю (node_modules, .git, генеровані директорії). Node 25.5.0 згадує доповнення до fs.watch, а docs описують ignore як опцію, яка може приймати glob/RegExp/function/array.[15]

Мінімальний приклад для dev-інструментів:

JS
import { watch } from 'node:fs';

watch('.', {
  recursive: true,
  ignore: ['**/node_modules/**', '**/.git/**'],
}, () => {});

У major-релізах Node часто боляче не через нові API, а через фіналізацію деprecation. SlowBuffer — показовий приклад такого прибирання.[16]

1) Що сталося з SlowBuffer

В deprecations docs Node прямо зазначено, що SlowBuffer прибрано і треба переходити на Buffer.allocUnsafeSlow(size).[16]

2) Як це виглядає “в полі”

Є реальний кейс, де бекенд падав на Node 25.x через dependency chain, який торкався SlowBuffer.prototype.[17]

3) Швидкий scan перед апгрейдом

BASH
rg -n "\bSlowBuffer\b" .

Потім pnpm why/npm ls, щоб знайти, хто тягне legacy-залежність.

Це короткий «бойовий» чекліст, який реально працює в командах.

  • 1) Тримай прод на LTS, а Node 25 додай у CI (матриця LTS + Current).[6]

  • 2) Проганяй тести з вимкненим Web Storage, щоб швидко локалізувати проблеми: NODE_OPTIONS="--no-experimental-webstorage".[7]

  • 3) Якщо зламалося — дивись туди, де вже зламалось у інших: nodejs/node #60704, Vitest #8757, Jest #15888.[5][4][3]

  • 4) Якщо тебе цікавлять фічі 25.4/25.5, винось їх у окремий експеримент (CLI/воркер), не в прод-бекенд “одним махом”.[9][12]

  • 5) Для monorepo підкрути вотчери: fs.watch({ ignore }) знижує шум і навантаження.[15]

  • 6) Для корпоративного CI за проксі: спробуй http.setGlobalProxyFromEnv() як просте глобальне рішення.[14]

Вердикт без фанатизму: Node 25 — дуже корисний як «індикатор майбутніх проблем» (CI), і корисний для окремих продуктів (CLI/агенти). Але для прод-бекенду LTS часто виграє саме стабільністю.

Скоріше чекати / LTS

Node рекомендує production тримати на Active/Maintenance LTS.[6]

Додати вже

Node 25 швидко покаже регресії залежностей (Web Storage) і legacy cleanup (SlowBuffer), без ризику інциденту в проді.[5][16]

Можна апгрейдити

--build-sea (25.5.0) + дозрівання 25.4.0 — це реальний DX-профіт. Просто тестуйте на target OS/шелах.[12][21]

Current має право «кусатися»

Current існує, щоб екосистема встигла адаптуватися. Якщо він ламає день — тримайте його в CI, а прод залишайте на LTS.[6]

Node.js 25 — це LTS?

Ні. Це Current (odd major). Node прямо пише, що production застосунки мають використовувати Active або Maintenance LTS.[6]

Чому Web Storage так гучно вистрілив?

Бо змінилася default-поведінка. `localStorage` став доступний без experimental-флага, а в Node він має іншу семантику (файл, 10MB, shared). Це зламало припущення тулінгу/тестів.[7][5][4]

Як швидко розблокувати CI, якщо все падає через localStorage?

Тимчасово вимкнути Web Storage через `NODE_OPTIONS="--no-experimental-webstorage"` або як флаг запуску. Це згадується в globals docs і фігурує в regression-тредах як workaround.[7][5]

SEA через --build-sea вже можна використовувати?

Так, але тестуйте на цільових OS/шелах. Є shell-specific issue на Windows Command Prompt.[21] Деталі конфігів і процесу — в SEA docs.[13]

Джерела в порядку появи у тексті (позиція в списку = номер [n]).

0

Найкраща стратегія для більшості команд: прод на LTS, Node 25 у CI як ранній детектор регресій, і окремі експерименти для фіч 25.4/25.5 (require(esm), compile cache, build-sea). Так ти отримуєш DX-профіт без “дня, який зламав localStorage”.

Пов'язані статті

growth

AI SEO / GEO у 2026: ваші наступні клієнти — не люди, а агенти

Пошук зміщується від кліків до відповідей. Боти та AI-агенти сканують, цитують, рекомендують і дедалі частіше купують. Дізнайтесь, що таке AI SEO / GEO, чому класичного SEO вже недостатньо, і як PAS7 Studio допомагає брендам перемагати у «агентному» вебі.

blogs

Найпотужніший чіп від Apple? M5 Pro і M5 Max б'ють рекорди

Аналітичний розбір Apple M5 Pro і M5 Max станом на березень 2026 року. Пояснюємо, чому ці чіпи можна вважати найпотужнішими професійними ноутбучними SoC від Apple, як вони виглядають на тлі M4 Pro, M4 Max, M1 Pro, M1 Max і що показують у порівнянні з актуальними Intel та AMD.

blogs

Artemis II і код, який веде до Місяця

У цьому блозі розбираємо місію NASA Artemis II, яка стартувала 1 квітня 2026 року, і пояснюємо, що вона насправді говорить про сучасну інженерію: бортове ПЗ, резервні контури, симуляції, телеметрію, людський контроль і дуже обережну роль ШІ в космічній сфері.

telegram-media-saver

Автоматичне тегування та пошук збережених посилань

Інтеграція з GDrive/S3/Notion для автоматичного тегування та швидкого пошуку через пошукові API

Професійна розробка для вашого бізнесу

Створюємо сучасні веб-рішення та боти для бізнесу. Дізнайтеся, як ми можемо допомогти вам досягти цілей.