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 に切り替える。
公開: 更新:
要約
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
この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。
よくある原因
- Route Handler に
export const runtime = 'edge'を付けたまま、内部でfs.readFile等を呼んでいる - 依存パッケージ(例: 暗号化ライブラリの一部、ネイティブビルドが必要な
sharpの設定、bcrypt)が裏で Node API を参照している process全体やBufferを Web 標準的でない使い方をしている- ネイティブビルドが必要な 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 API | Web 標準の代替 |
|---|---|
fs.readFile で静的ファイル | デプロイ時に import で取り込みバンドルに含める |
crypto.createHash | crypto.subtle.digest |
Node 18 未満の fetch | グローバル fetch(Edge は標準対応) |
Buffer | Uint8Array / 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 公式(新しいタブで開く) にまとまっている。