できない.dev

Vercel Edge Runtime で Node.js API(fs / child_process 等)が使えない

Edge Runtime は V8 isolate 上で動く Web 標準 API のみのサンドボックスで Node.js ではない。
fs / child_process / net / ネイティブモジュールは使えない。
Node API が必要なら runtime を nodejs に切り替える。

公開: 更新:

実行例あり(2026-09-24 に実環境で検証)

要約

Vercel Edge Runtime は Node.js ではなく V8 isolate 上で動く Web 標準 API のみのサンドボックス。fs, child_process などの Node コア API、ネイティブモジュールはすべて使えない。
症状の出方は Next.js のバージョンで異なり、webpack でビルドする Next.js 15 まで(14.2・15.5 で確認)は next build が「Module not found: Can't resolve 'fs'」で失敗するが、Turbopack でビルドする Next.js 16(16.3.5 で確認)は警告が出るだけでビルドが通り、リクエストした時点で「The edge runtime does not support Node.js 'fs' module.」の 500 エラーになる。
どちらもランタイムを Node に切り替えれば解消する。

実行例

node:20 のコンテナで Next.js 16.3.5 の next build を実行すると、runtime = "edge" のまま fs を import した route.js は警告が出るだけでビルドが終了コード 0 で通り、next start 後にそのルートへリクエストした時点で The edge runtime does not support Node.js 'fs' module. の HTTP 500 になった。runtime を "nodejs" に書き換えて再ビルドすると警告は消え、同じリクエストが 200 を返す。

$ npx next --version
Next.js v16.3.5
$ cat app/api/x/route.js   # runtime = "edge" のまま fs を使う
import fs from "fs";
export const runtime = "edge";
export async function GET() {
  const s = fs.readFileSync("/etc/hostname", "utf8");
  return new Response(s);
}
$ npx next build
▲ Next.js 16.3.5 (Turbopack)
✓ Running next.config took 6ms
 
  Creating an optimized production build ...
✓ Compiled successfully in 1769ms
  Running TypeScript ...
  Finished TypeScript in 3ms ...
  Collecting page data using 5 workers ...
⚠ The Edge Runtime is deprecated. You can use the "nodejs" runtime instead. Learn more: https://nextjs.org/docs/messages/edge-runtime-deprecated
⚠ Using edge runtime on a page currently disables static generation for that page
  Generating static pages using 5 workers (0/3) ...
✓ Generating static pages using 5 workers (3/3) in 262ms
Turbopack build encountered 1 warning:
./app/api/x/route.js:1:1
Warning: A Node.js module is loaded ('fs' at line 1) which is not supported in the Edge Runtime.
    Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
> 1 | import fs from "fs";
    | ^^^^^^^^^^^^^^^^^^^^
  2 | export const runtime = "edge";
  3 | export async function GET() {
  4 |   const s = fs.readFileSync("/etc/hostname", "utf8");
 
Ecmascript file had an error
 
  Finalizing page optimization ...
 
Route (app)
┌ ○ /
├ ○ /_not-found
└ ƒ /api/x
 
○  (Static)   prerendered as static content
ƒ  (Dynamic)  server-rendered on demand
 
終了コード: 0
$ npx next start -p 3000 > start.log 2>&1 &
$ curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost:3000/api/x
HTTP 500
$ grep -m1 -A1 "Error:" start.log
⨯ Error: The edge runtime does not support Node.js 'fs' module.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
$ sed -i 's/runtime = "edge"/runtime = "nodejs"/' app/api/x/route.js
$ npx next build
▲ Next.js 16.3.5 (Turbopack)
✓ Running next.config took 5ms
 
  Creating an optimized production build ...
✓ Compiled successfully in 375ms
  Running TypeScript ...
  Finished TypeScript in 1ms ...
  Collecting page data using 5 workers ...
  Generating static pages using 5 workers (0/4) ...
  Generating static pages using 5 workers (1/4) 
  Generating static pages using 5 workers (2/4) 
  Generating static pages using 5 workers (3/4) 
✓ Generating static pages using 5 workers (4/4) in 271ms
  Finalizing page optimization ...
 
Route (app)
┌ ○ /
├ ○ /_not-found
└ ƒ /api/x
 
○  (Static)   prerendered as static content
ƒ  (Dynamic)  server-rendered on demand
 
終了コード: 0
$ npx next start -p 3000 > start.log 2>&1 &
$ curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost:3000/api/x
HTTP 200

— 2026-09-24 時点の出力

検証環境

検証日
実行環境
node:20Debian GNU/Linux 12 (bookworm)
バージョン
  • Node.js 20.20.2
  • npm 10.8.2
  • Python 3.11.2
  • Git 2.39.5

この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。

よくある原因

  1. Route Handler に export const runtime = 'edge' を付けたまま、内部で fs.readFile 等を呼んでいる
  2. 依存パッケージ(例: 暗号化ライブラリの一部、ネイティブビルドが必要な sharp の設定、bcrypt)が裏で Node API を参照している
  3. process 全体や Buffer を Web 標準的でない使い方をしている
  4. ネイティブビルドが必要な NPM パッケージを import している

解決策

1. ランタイムを切り替える

最も単純な解決は Node ランタイムに戻すこと:

// app/api/foo/route.ts
export const runtime = "nodejs";  // 'edge' を外す

これで Node API が使えるようになる。
Edge の低レイテンシが必要な経路だけを Edge に残し、それ以外は Node に分けるのが基本戦略。
詳細な対応 API 一覧は Vercel Edge Functions 公式ドキュメント(新しいタブで開く) を参照。

2. Web 標準 API に置き換える

Node APIWeb 標準の代替
fs.readFile で静的ファイルデプロイ時に import で取り込みバンドルに含める
crypto.createHashcrypto.subtle.digest
Node 18 未満の fetchグローバル fetch(Edge は標準対応)
BufferUint8Array / TextEncoder

3. 依存ライブラリの Edge 対応版を探す

ライブラリの README に「Edge runtime support」「Cloudflare Workers compatible」と書かれているものを選ぶ。
例えば JWT は jose、暗号は @noble/hashes のようなピュア JS 実装を使う。

4. ジョブを分離する

Edge は「低遅延でリクエストを受け、軽い処理だけ」、Node は「重い処理・ファイル I/O・ネイティブ依存」と役割分担を明確にする。
Edge 経路から Node 経路へ fetch で内部呼び出しするのが定石。
Next.js 利用時の指針は Next.js Edge Runtime 公式(新しいタブで開く) にまとまっている。

この記事は役立ちましたか?