本文へ移動
verified onnext@16.3.5react@19
最終検証日 2026-09-26
Next.js道場

Module not found: Can't resolve 'fs' の直し方

実際に出るエラー

Error: Module not found: Can't resolve 'fs'

Import trace:
  Server Component:
    ./app/view.tsx
    ./app/page.tsx

https://nextjs.org/docs/messages/module-not-found

Client Component から fs などのサーバー専用のモジュールにたどり着いたときに出るビルドエラーです。

何が起きているか

'use client' を書いたファイルは、ブラウザ用にも束ねられます。そこから読み込んだファイルも、その先で読み込んでいるファイルも、すべて束ねる対象です。

ブラウザにはファイルを読む仕組みがありません。だから、束ねる途中で fs にたどり着くと、行き先が見つからずにビルドが止まります。

'use client'
 
import fs from 'fs'   // ← ブラウザ用に束ねられない
どこで止まるか
  1. Build
    use client のファイルを見つける

    ここから先はブラウザ用にも束ねる。

  2. Build
    import を順にたどる

    そのファイルが読み込むファイルも、その先も全部。

  3. Build
    fs にたどり着く

    ブラウザ用の行き先が無い。Can't resolve 'fs' で止まる。

自分で fs を書いていないのに出る

いちばん多いのはこの形です。使っている関数ではなく、読み込んだファイルごと束ねられます。

// lib/mail.ts
import { connect } from 'net'   // ← サーバー専用
 
export function sendMail(host: string) {
  return connect(25, host)
}
 
export function isEmail(v: string) {   // ← ブラウザでも使いたい
  return /^[^@\s]+@[^@\s]+$/.test(v)
}
// app/form.tsx
'use client'
 
import { isEmail } from '../lib/mail'   // ← isEmail しか使っていなくても止まる

実機で確かめました。Can't resolve 'net' で止まります。エラーが指す場所は lib/mail.ts の1行目ですが、直すべきは form.tsx の import です。

どのモジュールで止まるか

Node.js の組み込みモジュールを、1つの Client Component から読み込んで確かめました。

Client Component から読み込んだとき(実機で確かめた)
モジュールビルド
fs止まる
net / tls / dns止まる
child_process止まる
path / os / crypto止まらなかった

データベースやメールのライブラリは、中で net や tls を使っていることが多いです。そうしたライブラリを Client Component から読み込むと、同じ形で止まります。

止まらなかったものも、ブラウザで Node.js と同じように動くとは限りません。サーバーの処理はサーバーに置いてください。

直し方

1. ファイルを分ける

ブラウザでも使う関数と、サーバー専用の関数を、別のファイルにします。

// lib/validate.ts  ← ブラウザでも使う
export function isEmail(v: string) {
  return /^[^@\s]+@[^@\s]+$/.test(v)
}

フォームは lib/validate.ts だけを読み込みます。

2. サーバーで読んで、結果を渡す

ファイルの中身を画面に出したいなら、Server Component で読んで、文字として Client Component に渡します。

// app/page.tsx(Server Component)
import { readFileSync } from 'node:fs'
import View from './view'
 
export default function Page() {
  const text = readFileSync(process.cwd() + '/data.txt', 'utf8')
  return <View text={text} />
}

実機で、読んだ文字が画面に出ることを確かめました。

3. サーバー専用のファイルに印を付ける

サーバー専用のファイルの先頭に import 'server-only' を書くと、Client Component から読み込んだ時点で、サーバー専用のファイルだと分かる文言で止まります。Can't resolve より原因が分かりやすくなります(server-only の解説)。

出典

このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。

理解できたか試す

では、このコードはどうなりますか。

問い合わせフォームで、送る前にメールアドレスの形を確かめたくなりました。メール送信のファイルに isEmail があったので、フォームから読み込みました。フォームが使っているのは isEmail だけです。ビルドするとどうなりますか。

この問題を解くこのテーマの問題 3 問