Next.jsでSSR中にfsを触ったらエラーが起きたので整理しておきます。
Next.jsのレンダリングの方法
Next.jsがサーバーサイドでページをレンダリングする方法にはSSG (Static Site Generation), SSR (Server Side Rendering), ISR (Incremental Static Regeneration), SSG (fallback)などがあります。
SSG
ビルド時にサーバーサイドでページをレンダリングします。動的パスの場合はgetStaticPathsでパスを指定します。
SSR
リクエストがあったときにサーバーサイドでページをレンダリングします。
ISR
getStaticPathsでrevalidateを指定すると適用されます。リクエストがあったときは静的なページを返しますが、revalidateで指定した期間が過ぎていたら裏で再度レンダリングします。
SSG (fallback)
getStaticPathsでfallback: trueを指定すると適用されます。ビルドされていないページのパスにリクエストが来たら、その場でページをレンダリングします。
Next.jsのサーバーサイド環境は2つある
ビルド環境
next dev, next build, next startなどが動いている環境です。getStaticPathsで指定されたページのレンダリングは常にこちらで行われます。
ここではプロジェクトに含まれるすべてのファイルにアクセスできます。
自前のサーバーやコンテナ、Herokuなどでnext startで動かしている場合は常にビルド環境になります。
サーバーレスモード
next.config.jsでtarget: 'serverless'が指定されていると、ビルド時にページごとに単一のjsファイル (lambda) が生成されます。SSR, ISR, SSG (fallback)など、リクエスト時のレンダリングはこのlambdaを動かすことで行われます。
Vercelのドキュメントに書かれているように、原則としてlambdaからはファイルシステムにアクセスできません。webpackの設定をいじればできないことはないですが、基本的にハックの範疇なので将来的に動かなくなる可能性があります。pages/api/の下にあるAPI Routesについても、同じくファイルシステムは触ってはいけません。
サーバーレスモードはVercelやNetlifyで適用されます。
ビルド環境かサーバーレスモードかを判定するには
Vercelの場合は環境変数にCI=1が設定されていればビルド環境、されていなければサーバーレスモードです。Netlifyについては把握していませんが、少なくとも自前で環境変数をセットしておけば判定できると思います。
サーバーレスモードからファイルにアクセスするには
まずはSSRでなくSSGで対応できないか、リソースをlambdaに含められないかを検討しましょう。JSONを読みたい場合はfsから読まずにimportするなどの方法があります。
どうしてもSSR中にファイルを読みたい場合はネットワークからフェッチする必要があります。public/かS3などのストレージに置きましょう。
まとめ
VercelやNetlifyにデプロイされているNext.jsアプリケーションで、ビルド中以外にファイルシステムを触ってはいけない。