Fix the 'can't resolve module' error in Next.js

By

Fix the Next.js Module not found: Can't resolve 'fs' error, which happens when you import a Node module helper but never call it inside getStaticProps().

~~~

I ran into this issue with Next.js:

Module not found: Can’t resolve ‘fs’

This error means Next.js tried to include a Node.js-only module in the browser bundle. fs reads files from disk. Browsers don’t have a filesystem to read from, so the module doesn’t exist there, and the build fails.

The fix is making sure the code that touches Node.js modules only runs on the server. Let me show you how I hit this, because the cause was not obvious.

How I hit the error

In a Next.js page you can import methods from a file that loads Node.js modules.

This is fine, as long as you also use the imported method in getStaticProps().

Example, I had this code:

import { getData } from '../lib/data'

//...

export async function getStaticProps() {
  const data = getData()
  return {
    props: {
      data,
    },
  }
}

When I commented const data = getData(), Next started giving me the error 'fs' module not found because fs was the first module I imported in lib/data.

It might happen with any other Node library you import first. path, child_process, net: anything that only exists in Node.js.

Why does this happen?

A Next.js page runs in two places: on the server and in the browser. When Next.js builds the browser bundle, it strips out getStaticProps() along with every import that is used only inside it.

That last part is the key. The elimination is based on usage. As long as getData() is called inside getStaticProps(), Next.js knows the import is server-only and drops it from the client bundle.

The moment I commented out that call, getData stopped looking server-only. The import stayed in the client bundle, the bundler followed it into lib/data, found require('fs'), and gave up.

This is why anything in getStaticProps() is only called in a server environment, but if we don’t invoke the Node.js function in there, Next.js can’t know that.

The fix

Either call the imported function inside getStaticProps() (or getServerSideProps()), or remove the import while you don’t need it.

Commenting out the usage while keeping the import is the one combination that breaks. When I want to temporarily disable the data loading, I now comment out the import line too.

Tagged: Next.js · All topics
~~~

Related posts about next: