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 — і раптом «localStorage» валить збірку

Є два типи апгрейду 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]

Section prologue screenshot

Міні-хронологія Node 25: чому важливі не тільки «25.0.0», а й 25.4 та 25.5

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]

Швидка термінологія, щоб читати без «гугління кожні 2 хвилини»

Мінімум понять, без яких 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]

Node 25.0.0: що нового «в базі» і де тут практична користь

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

V8

14.1

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

Web Storage

enabled by default

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

Security posture

permissions

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

Legacy cleanup

deprecations

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

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

Section node-25-0 screenshot

Web Storage by default: чому це вистрілило і як це виглядає в реальних проєктах

Проблема не в тому, що 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]

Section webstorage-saga screenshot

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

Section webstorage-saga screenshot

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

Section webstorage-saga screenshot

Node 25.4.0: require(esm) стає stable (і це реально міняє міграції)

Це той клас змін, який не «кричить» у реліз-нотах, але економить тижні в репозиторіях, де 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]

Section require-esm screenshot

Module compile cache: portable режим і “доросла” документація — що це дає в CI/контейнерах

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]

Section compile-cache screenshot

Node 25.5.0: `node --build-sea` робить SEA «однією командою»

Це одна з найбільш «продуктових» змін лінійки: тепер збірка 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]

Section sea-build-sea screenshot

Ops QoL: проксі з env і зрозумілий шлях для корпоративних мереж

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

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

JS
import http from 'node:http';

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

API

http.setGlobalProxyFromEnv()

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

Порада

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

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

Сумісність

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

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

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

Section ops-qol screenshot

Monorepo-біль: `fs.watch({ ignore })` як простий спосіб зменшити шум

Якщо у вас великий репозиторій, вотчери — це окремий світ болю (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/**'],
}, () => {});

Breaking changes: як Node 25 ламає залежності не фічами, а «прибиранням legacy»

У 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-залежність.

Upgrade playbook: як додати Node 25 так, щоб він давав користь, а не біль

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

  • 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.js 25 вже зараз

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

Продакшн бекенд

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

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

CI / сумісність

Додати вже

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

CLI / агенти

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

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

Психологічно

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

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

Sources

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

Часті запитання

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]

Якщо коротко: забери користь з Node 25, але не бери ризик у прод “в лоб”

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

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

Ознайомтеся з іншими корисними статтями

growth15 лютого 2026 р.

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

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

Читати →
telegram-media-saver8 січня 2025 р.

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

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

Читати →
services1 січня 2025 р.

Розробка Telegram-ботів та автоматизація

Професійна розробка Telegram-ботів та автоматизація бізнес-процесів: чат-боти, AI-асистенти, інтеграції з CRM та автоматизація процесів.

Читати →
backend-engineering15 лютого 2026 р.

Bun vs Node.js у 2026: чому Bun відчувається швидшим (і як перевірити застосунок перед міграцією)

Bun — це швидший all-in-one JavaScript toolkit: runtime, пакетний менеджер, бандлер і тест-раннер. Розбираємо, що реально дає приріст (з бенчмарками), що може зламатися, і як отримати безкоштовний readiness-аудит через @pas7-studio/bun-ready.

Читати →

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

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