Next.js で「Module not found: Can't resolve 'fs'」が解決できない
fs などの Node コアモジュールをクライアントに含まれるコードで import すると出る。
サーバー専用コードへ移すか、Server Component / Route Handler 側でのみ使う。
公開:
要約
Module not found: Can't resolve 'fs' は、fs や path などブラウザに存在しない Node コアモジュールを、クライアントバンドルに含まれるコードから import したときに出る。
ファイルに 'use client' を付けると、その import 連鎖はすべてクライアントに含まれる。fs はサーバーにしか無いのでバンドルできず、解決に失敗する。
対策の基本は、サーバー専用の処理を Server Component や Route Handler 側へ寄せること。
よくある原因
- クライアント境界の巻き込み:
'use client'のファイル(またはそこから import した先)でfsを参照している。 - サーバー専用コードの混入: ファイル読み込みなどサーバー用ユーティリティをクライアントから import している。
- 依存ライブラリ経由: ライブラリが内部で Node コアモジュールに依存し、クライアント側に引き込まれている。
解決策
1. サーバー側へ処理を移す(推奨)
// app/page.tsx (Server Component: 'use client' を付けない)
import { readFileSync } from "node:fs";
export default function Page() {
const data = readFileSync("data.json", "utf8");
return <pre>{data}</pre>;
}fs を使う読み込みは Server Component 側で行い、結果だけをクライアントへ渡す。
2. server-only でガードする
import "server-only";このモジュールを import したファイルがクライアントに含まれるとビルドが失敗するため、混入を早期に検知できる。
3. resolve.fallback で空に割り当てる(最終手段)
// next.config.js (webpack 利用時)
module.exports = {
webpack: (config) => {
config.resolve.fallback = { fs: false };
return config;
},
};どうしてもリファクタできない場合の逃げ道。
Turbopack を使う場合は turbopack.resolveAlias で同様に空モジュールへ割り当てる。
まずはリファクタで fs をクライアントから外すのが本筋。