Node.js 27 Alphaを26 LTSと比べて検証|27で書いたv8.serializeのデータは26で読めず、ヒープ上限とHTTPの既定値も変わる
Node.jsが新しいリリース日程で初めての「Alpha」版、27.0.0-alphaを公開した
Node.jsの開発チームは2026年10月29日、Node.js 27.0.0-alpha.0.0.0を公開しました。Node.jsは27から、新しい大型版を年に1回、4月に出す日程へ切り替えます。リリース日程の告知によると、正式な27.0.0は2027年4月に出て、その前の約6か月を「Alpha」と呼ぶ試験期間にあてます。Alphaは、ライブラリの作者やCI(自動テストの仕組み)が、互換性を壊す変更へ早めに備えるための版です。本番での利用は想定されておらず、APIは版ごとに変わることがあります。
今回のAlphaには、JavaScriptエンジンのV8を14.6から15.6へ上げる更新と、互換性を壊す変更(semver-major)が50件以上入っています。互換性への影響としてリリースノートが挙げている変更の1つが、v8.serialize()やstructuredClone()が作るデータの形式が変わり、古いNode.jsで読めなくなる点です。
この記事では、長期サポート版の26.13.0とAlphaの公式バイナリを手元のMacとDockerで並べて動かし、リリースノートの主な変更が実際にどう現れるかを確かめた結果をまとめます。27を使う予定のあるライブラリやサーバーで、2027年4月までに直しておく点が分かります。
3分で把握
26.13.0とAlphaを並べて動かすと、3つの違いがはっきり出た
2026年11月3日、macOS 27.0.1(Apple Silicon)とDocker上のUbuntu 24.04で、公式バイナリを使って確認しました。
保存したデータ
27で書くと26で読めない
v8.serialize()の結果を26のv8.deserialize()で読むとエラーになった。逆向きは読めた。
メモリの上限
4GB超〜8GBのコンテナで大きくなる
何も指定しないときのヒープ上限が、6GBのコンテナで2144MiBから3168MiBに上がった。
HTTPサーバー
既定値が2つ変わった
接続を保つ時間が5秒から65秒に。req.headers.hasOwnProperty()はTypeErrorになった。
27.0.0は2027年4月に公開され、それまでの半年がAlphaの期間になる
これまでのNode.jsは、偶数の版が長期サポート版(LTS)になり、奇数の版は短期間で終わる形でした。27からはこの区別がなくなり、すべての版がLTSになります。版の番号は最初に公開される年に合わせ、27.0.0は2027年、28.0.0は2028年に出ます。新しい日程を、27を例に並べると次のようになります。
2026年10月〜2027年3月|Alpha
互換性を壊す変更も入る試験期間。10月29日に最初のAlphaが出た。署名付きで公開され、本番での利用は想定しない。
2027年4月|27.0.0を公開(Current)
新機能を受け取る段階が6か月続く。
2027年10月|LTSへ
長期サポート版として30か月続く。
2030年4月|サポート終了
27.0.0の公開から36か月。
出典: Node.jsの告知「Evolving the Node.js Release Schedule」(2026年3月10日更新)。告知は、正式な日程はnodejs/Releaseのschedule.jsonで管理するとしています。
手元では、nodejs.org/distからAlphaと26.13.0のmacOS版・Linux版を取得し、同じ場所のSHASUMS256.txtと一致することを確かめてから使いました。AlphaのmacOS版でprocess.versionsを表示すると、V8は15.6.75.25、ネイティブアドオンの互換番号(NODE_MODULE_VERSION)は153でした。26.13.0は147なので、V8の機能を直接使うネイティブアドオンは、27向けにビルドし直す必要があります。
27で保存したv8.serializeのデータは、26で読むとエラーになる
v8.serialize()は、JavaScriptのオブジェクトをMapやDateを含めてバイト列に変える関数です。キャッシュをファイルに保存したり、別のプロセスへ渡したりするときに使われます。structuredClone()や、ワーカーとの間でデータをやり取りするpostMessage()も同じ形式を使っています。リリースノートは、27ではこの形式が新しくなり、古いNode.jsでは読めないと書いています。
同じオブジェクトを26.13.0とAlphaでそれぞれv8.serialize()してファイルに保存し、両方の版でv8.deserialize()を使って読み戻しました。
node v26.13.0: wrote 54 bytes, header ff0f
node v27.0.0-alpha.0.0.0: wrote 54 bytes, header ff10
file from 26 -> node v26.13.0: read OK
file from 26 -> node v27.0.0-alpha.0.0.0: read OK
file from 27 -> node v26.13.0: Error: Unable to deserialize cloned data due to invalid or unsupported version.
file from 27 -> node v27.0.0-alpha.0.0.0: read OK
26で書いたデータ
26でも27でも読める
27へ上げても、これまで保存したデータはそのまま読み込める。
27で書いたデータ
27だけが読める
先頭の版番号の1バイトが0x0fから0x10に変わり、26は「対応していない版」として読み込みを止めた。
影響が出るのは、Node.jsの版が混在する場面です。たとえば、複数のサーバーを順番に27へ入れ替える間に、27のサーバーが共有のキャッシュへ書いたデータを、まだ26のサーバーが読むと、この例外が起きます。27へ上げたあとに問題が見つかって26へ戻した場合も、27の間に保存したデータは読めなくなります。版をまたいで保存するデータは、JSONのように形式が決まったものに変えておくと、入れ替えの順番を気にせずに済みます。
同じ変更で、V8のコードキャッシュの識別に使うv8.cachedDataVersionTag()は、V8の修正が入るたびに値が変わるようになりました。手元でも26.13.0とAlphaで値が違っていました。この値を設定ファイルなどに固定で書いているツールは、27の修正版が出るたびに作り直しになります。
メモリ4GB超〜8GBのコンテナでは、何も指定しないときのヒープ上限が大きくなる
V8のヒープは、JavaScriptのオブジェクトを置くメモリの領域です。その上限は--max-old-space-sizeで指定でき、指定しなければNode.jsが自動で決めます。27では、この自動の上限が「物理メモリの半分(256MB以上、4GB以下)」になりました。
違いはメモリの量で変わるため、DockerでUbuntu 24.04のコンテナにメモリの上限を付け、Linux版の26.13.0とAlphaでv8.getHeapStatistics()のheap_size_limitを比べました。
ヒープ上限の比較(--max-old-space-sizeを指定しない場合)
4GBまでは同じ、5GB以上の測った範囲では27のほうが大きい
コンテナのメモリ 2GB
コンテナのメモリ 4GB
コンテナのメモリ 6GB
--memory 8g(仮想マシンの約7.75GiBを超えるため、実質的に上限なし)
Docker Desktop(仮想マシンのメモリ約7.75GiB)上のUbuntu 24.04で、docker run --memoryを指定して計測。1GBと3GBでも両方の版は同じ値でした(536MiB、1632MiB)。バーの長さは最大値(4064MiB)を100%とした比率です。macOS(メモリ32GB)では、どちらの版も4192MiBでした。
Dockerで測った約7.75GiBまでの範囲では、26もメモリのおよそ半分を上限にしていましたが、2144MiBで頭打ちになりました。27はヒープの上限が4GBに届くまでメモリの半分のまま伸びるため、メモリが4GBを超えると差が出ます。6GBのコンテナでは約1.5倍、仮想マシン全体の約7.75GiBを使える状態では約1.9倍で、27はそこまでヒープを使ってから、メモリ不足のエラーを出すことになります。一方、メモリ32GBのmacOSでは両方とも4192MiBで同じだったため、メモリの大きい環境では差が小さいか、出ないことがあります。同じコンテナでほかのプロセスも動かしている場合や、ヒープ以外のメモリを多く使うアプリでは、Node.jsのエラーより先にコンテナ自体がメモリの上限で止められることがあります。リリースノートも、これまでの既定値を前提にしていたアプリは--max-old-space-sizeを明示するよう勧めています。
リリースノートは同じ項目で、BufferとArrayBufferのメモリもヒープの上限に数えるようになったと説明しています。今回のAlphaのmacOS版では、--max-old-space-size=128で起動して2GiBのBufferを保持しても、26.13.0と同じく処理が続き、Bufferの分はヒープの外(external_memoryの約2050MiB)に数えられていました。この扱いは今後のAlphaで変わる可能性があるため、Bufferを多く使うアプリは、Alphaが更新されるたびにCIで確かめると安心です。
HTTPサーバーでは、接続を保つ時間とreq.headersの扱いが変わった
HTTPの既定値の変更も、サーバーを動かすと確かめられます。http.createServer()で作ったサーバーのkeepAliveTimeoutを表示し、ローカルから1回リクエストを送って、req.headersを調べました。
===== v26.13.0
keepAliveTimeout default: 5000 ms
req.headers: {"proto":"Object.prototype","hasOwnProperty":true,"hasOwn":true}
===== v27.0.0-alpha.0.0.0
keepAliveTimeout default: 65000 ms
req.headers: {"proto":"null","hasOwnProperty":"TypeError: req.headers.hasOwnProperty is not a function","hasOwn":true}
req.headersのプロトタイプがnullに
req.headers.hasOwnProperty('host')は27でTypeErrorになった。
直し方: Object.hasOwn(req.headers, 'host')に書き換える。26と27の両方でtrueを返した。
keepAliveTimeoutが65秒に
応答後に次のリクエストを待つ時間が、5秒から65秒に延びた。
既定値の5秒を前提にしているサーバーは、27でも同じ値になるよう明示しておく。
req.headersは、リクエストのヘッダーを名前と値の組で持つオブジェクトです。27ではプロトタイプを持たないオブジェクトになり、hasOwnProperty()やtoString()のような、ふつうのオブジェクトが受け継ぐメソッドが使えなくなりました。古いミドルウェアや自作のヘッダー処理でreq.headers.hasOwnProperty(...)と書いていると、27では最初のリクエストで例外になります。
keepAliveTimeoutは、1回の応答のあと、同じ接続で次のリクエストを待つ時間です。65秒に延びると、次のリクエストを待つ接続がそれだけ長く開いたままになるため、多くのクライアントから接続を受けるサーバーでは、同時に開いている接続の数が増えることがあります。前段にロードバランサーを置く構成では、ロードバランサー側が接続を保つ時間より短い値だと、ロードバランサーがまだ使うつもりの接続をNode.jsが先に閉じることがあり、長めの既定値はこの食い違いを起こしにくくします。
domainモジュールなどの警告と、使えるようになる新しい書き方
27では、すぐには動かなくならないものの、実行すると警告が出るようになった機能もあります。手元では、domainモジュールを読み込むとDEP0032の警告が、1つのHmacでdigest()を2回呼ぶとDEP0206の警告が、27だけで出ました。どちらも26では警告なしで動いています。CIのログに新しいDeprecationWarningが出ていないかを見ると、将来の版で削除される前に見つけられます。
V8 15.6で、新しいJavaScriptの機能も使えるようになりました。26ではどれもTypeErrorになった3つが、Alphaでは動きました。
Math.sumPrecise([1e20, 0.1, -1e20]) // 0.1(ふつうに足すと0)
[...Iterator.zip([[1, 2], ['a', 'b']])] // [[1,"a"],[2,"b"]]
[1, 2, 3].values().join('-') // "1-2-3"
Math.sumPrecise()は、桁の大きく違う数を足しても誤差が出にくい合計の関数です。Iterator.zip()は複数の並びを1つずつ組にして取り出します。使い始めたコードは26では動かないので、ライブラリで使う場合は、対応するNode.jsの版の範囲を決めてからにします。
27に備えて、いまのうちに確かめる4つのこと
Alphaは試験用の版です。本番はいまの版のまま、CIにだけ足しておくと、ここまでの変更が自分のコードに当たるかを2027年4月より前に確かめられます。今回の検証から、優先して確かめる点を順に並べます。
1. 版をまたいで保存しているv8.serializeのデータを探す
キャッシュやジョブのキューにv8.serialize()の結果を保存していないか、コードをv8.serializeで検索する。入れ替え中に26と27が同じデータを読み書きするなら、JSONなどへの切り替えを計画する。
2. コンテナで動かすアプリは--max-old-space-sizeを明示する
コンテナのメモリ上限から、ほかのプロセスとヒープ以外で使う分を引いた値を目安に、MB単位で指定する。明示した値は26でも27でも同じように使われる。
3. req.headers.hasOwnPropertyを検索して書き換える
Object.hasOwn()または'host' in req.headersに変える。keepAliveTimeoutに頼っているサーバーは値を明示する。
4. CIにAlphaを足し、警告とネイティブアドオンを確かめる
テストを流し、新しいDeprecationWarningと、ネイティブアドオンの読み込みエラー(NODE_MODULE_VERSION 153)が出ないかを見る。失敗しても本番の版はそのまま使い続けられる。
まとめ:Alphaで当たる変更を見つけ、27.0.0の公開前に直しておく
Node.js 27.0.0-alphaは、年1回の新しい日程で出た最初の試験版です。26.13.0と並べて動かすと、27で書いたv8.serialize()のデータが26で読めないこと、メモリ4GB超〜8GBのコンテナでヒープの上限が大きくなること、HTTPサーバーのreq.headersとkeepAliveTimeoutの扱いが変わることを、それぞれ手元で確かめられました。
どれも、コードの検索と設定の明示で事前に備えられる変更です。26は2029年4月までサポートが続くので、本番の版を急いで変える必要はありません。CIにAlphaを足して変更に当たる箇所を洗い出しておけば、2027年4月の27.0.0の公開に合わせて、落ち着いて切り替えられます。
参考資料
- Node.js 27.0.0-alpha.0.0.0 (Alpha)(Node.js、2026年10月29日)。V8 15.6、シリアライズ形式の変更、ヒープ上限の既定値、互換性を壊す変更の一覧
- Evolving the Node.js Release Schedule(Node.js、2026年3月10日更新)。年1回のリリース、Alphaの位置付け、27の日程
- Node.js 26.13.0 (LTS)(Node.js、2026年10月28日)。比較に使った長期サポート版












