Workers のモジュールレジストリが再構築され、Node.js 互換の解決へ。`new_module_registry` フラグでオプトイン
Cloudflare が 2026-09-09、Workers ランタイム(workerd)のモジュールレジストリを書き直したと公式ブログで解説した。モジュール指定子をファイルパスではなく URL として扱う方式へ変更し、Node.js のモジュール解決仕様と整合させた。`import.meta.url` / `import.meta.resolve()` の動作、`node:` 組み込みの同一インスタンス解決、ES モジュールへの `require()` の Node.js 準拠などが直る。遅延コンパイルとコードキャッシュ共有も入る。適用には `new_module_registry` 互換性フラグが必要で、既定オンの日付はまだ設定されていない。
ニュース原文を読む ↗要約
Cloudflare は 2026-09-09、Workers ランタイム(workerd)の モジュールレジストリを一から書き直したと公式ブログで解説しました。中心にあるのは、モジュール指定子(specifier)をファイルシステムのパスではなく URL として扱うという方針転換です。
**背景には、Workers に載せられるものが変わったことがあります。**Node.js API が既定で有効になり、Worker のサイズ上限が全プランで 64 MiB へ拡大しました。その結果、これまで載せられなかった規模の既存 Node.js アプリケーションを、そのまま Workers へ持ち込めるようになりました。ところが、旧レジストリはパスベースで解決を行っていたため、Node.js 側の仕様と食い違う挙動が表面化していました。
直った項目は、いずれも「Node.js では動くのに Workers では動かない」種類のものです。import.meta.url、import.meta.main、import.meta.resolve() が正しく動作します。指定子がクエリ文字列やフラグメントを含む実 URL として解析されます。node: 組み込みモジュールは、どの経路で import しても同一インスタンスに解決されます。import attributes が仕様どおり検証されます。ES モジュールに対する require() が、**Node.js の require(esm) ルールに従います。**読み込み経路が違ってもエラークラスとメッセージが統一されます。WebAssembly の source phase import にも対応します。
性能面の変更も入っています。モジュールは最初に import された時点で遅延コンパイルされるようになりました(従来は事前に一括コンパイル)。加えて、V8 isolate のレプリカ間でコードキャッシュを共有し、メモリの重複を減らします。
適用には明示的なオプトインが必要です。wrangler.toml の互換性フラグへ new_module_registry を指定します。公式は「既定で有効になる日付(default on date)はまだ設定されていない」と明記しており、放置しても自動的に切り替わることはありません。
何が変わったか
- モジュール指定子をファイルパスではなく URL として解決する新レジストリを実装
import.meta.url/import.meta.main/import.meta.resolve()が正しく動作する- 指定子がクエリ文字列・フラグメントを含む実 URL として解析される
node:組み込みは import 経路によらず同一インスタンスに解決される- import attributes が仕様どおり検証される
- ES モジュールへの
require()が Node.js のrequire(esm)ルールに従う - 読み込み経路によらずエラークラスとメッセージが統一される
- WebAssembly の source phase import に対応
- モジュールの遅延コンパイル(最初の import 時)と、isolate レプリカ間のコードキャッシュ共有
- 前提として Node.js API が既定で有効、Worker サイズ上限は全プラン 64 MiB
- 適用は
new_module_registry互換性フラグによるオプトイン。既定オン日は未設定
業務インパクト(一般企業向け)
この更新が効くのは、既存の Node.js 資産を Workers へ移そうとしている組織です。
エッジ実行環境への移行は、レイテンシとコストの両面で魅力があります。一方で、実際に手を付けると**「なぜか import が通らない」という段階で止まる**ことがよくあります。ライブラリが内部で import.meta.url を使っている、require() と import が混在している、node:fs を別の書き方で読んでいる。**個々は小さな食い違いですが、原因の特定に時間がかかる種類の問題です。**しかもライブラリの中で起きるため、自分のコードを直しても解決しません。
今回の変更は、この食い違いを仕様レベルで揃えにいくものです。「URL として扱う」という一見地味な方針転換が効くのは、Node.js のモジュール解決がもともと URL ベースの仕様に沿っているからです。パスベースの実装で近似していたものを、本来の形に合わせた。だからこそ、直った項目が広い範囲に散らばっています。
**判断としては、急ぐ理由がありません。**オプトインであり、既定オン日も設定されていません。**フラグを立てなければ、今日と同じ挙動が続きます。**したがって、いま安定して動いている Worker に対して慌てて適用する必要はありません。
**むしろ価値があるのは、次の2つの場面です。**1つは、移植を検討していて過去に断念した案件です。当時ぶつかった問題が、原因不明の import エラーだったなら、再挑戦する価値があります。もう1つは、これから新規に Workers へ載せるアプリです。最初からフラグを立てておけば、後から挙動が変わる心配がありません。
**注意すべきは、フラグを立てた後の検証です。**モジュール解決の挙動が変わるということは、今まで「偶然動いていた」import が動かなくなる可能性もあるということです。特に require() と ES モジュールが混在しているコードベースでは、Node.js 準拠になった結果として挙動が変わる箇所が出ます。本番へ入れる前にステージングで全経路を通すのは、この種の変更では省略しない方がよい工程です。
**サイズ上限 64 MiB という前提も、あわせて押さえておく価値があります。これは全プラン共通で、圧縮後バンドルサイズの制限も撤廃されています。「エッジ実行環境はサイズ制約が厳しいから既存アプリは載らない」という前提で検討を打ち切っていた組織は、その前提を更新する必要があります。**数年前の調査結果をそのまま持っている場合、判断の土台が古くなっています。
副業・個人活用視点
個人開発者にとっては、単純に移植の成功率が上がる話です。
Cloudflare Workers は、個人が小さなサービスを出す先として費用面で有利です。無料枠が広く、常時起動のサーバーを持たずに済みます。**問題は、npm で拾ってきたライブラリが動くかどうかが事前に読めないことでした。**動くものは動く、動かないものは理由が分かりにくい。**この不確実性そのものが、Workers を選びにくくしていた要因です。**Node.js の解決仕様に寄せられたことで、この読みにくさは減ります。
受託やクライアントワークでは、選択肢が広がるという意味があります。「この処理はエッジで動かせますか」と聞かれたとき、従来はやってみないと分からないという返事になりがちでした。ライブラリ依存の食い違いが読めないからです。仕様が揃うほど、**着手前に判断できる範囲が広がります。**見積もりの精度に直結する話です。
**フラグ運用は、そのまま実務の作法として身につけておく価値があります。Cloudflare の互換性フラグは、「新しい挙動を選べるが、選ぶまでは変わらない」**という設計です。既定オン日が設定されると、そこからは自動で切り替わります。**つまり、日付が発表された時点が対応の開始点になります。今回はまだ未設定なので、「日付が出たら動く」という状態で待っていれば十分です。**逆に、フラグの存在自体を知らないと、既定オンの日に何が起きたか分からなくなります。
**新規案件では、最初から立てておくのが得策です。**既存の稼働中 Worker に後から適用すると検証コストがかかりますが、新規なら最初からその挙動で作るだけです。将来の既定オンに備える意味でも、コストはゼロに近いところで済みます。
**遅延コンパイルとコードキャッシュ共有は、体感に出る可能性があります。**特にモジュール数の多いアプリでは、起動時に全部をコンパイルしないぶん、初回応答が早くなることが期待できます。**ただし公式は具体的な数値を出していません。**期待値として持っておく程度にして、実際の効果は自分の環境で測ってください。