Next.js: Module not found: Can't resolve 'fs'

Created on 5 Jul 2019  ·  13Comments  ·  Source: vercel/next.js

Bug report

Describe the bug

I'm using the popular find-up npm package, which has locate-path as a dependency. locate-path requires fs within it's code.

When I attempt to run my app I get the following error message:

[ error ] ./node_modules/locate-path/index.js
Module not found: Can't resolve 'fs' in 'C:\...\node_modules\locate-path'
Could not find files for /index in .next/build-manifest.json
Promise { <pending> }
ModuleNotFoundError: Module not found: Error: Can't resolve 'fs' in 'C:\...\node_modules\locate-path'
    at factory.create (C:\...\node_modules\webpack\lib\Compilation.js:823:10)
    at factory (C:\...\node_modules\webpack\lib\NormalModuleFactory.js:397:22)
    at resolver (C:\...\node_modules\webpack\lib\NormalModuleFactory.js:130:21)
    at asyncLib.parallel (C:\...\node_modules\webpack\lib\NormalModuleFactory.js:224:22)
    at C:\...\node_modules\neo-async\async.js:2830:7
    at C:\...\node_modules\neo-async\async.js:6877:13
    at normalResolver.resolve (C:\...\node_modules\webpack\lib\NormalModuleFactory.js:214:25)
    at doResolve (C:\...\node_modules\enhanced-resolve\lib\Resolver.js:184:12)
    at hook.callAsync (C:\...\node_modules\enhanced-resolve\lib\Resolver.js:238:5)
    at _fn0 (eval at create (C:\...\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:15:1)
    at resolver.doResolve (C:\...\node_modules\enhanced-resolve\lib\UnsafeCachePlugin.js:37:5)
    at hook.callAsync (C:\...\node_modules\enhanced-resolve\lib\Resolver.js:238:5)
    at _fn0 (eval at create (C:\...\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:15:1)
    at hook.callAsync (C:\...\node_modules\enhanced-resolve\lib\Resolver.js:238:5)
    at _fn0 (eval at create (C:\...\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:27:1)
    at resolver.doResolve (C:\...\node_modules\enhanced-resolve\lib\DescriptionFilePlugin.js:42:38)

I created an issue in the locate-path repo and they have confirmed the issue is not with them, but likely with webpack. I don't use webpack in my app so the issue must be arising from Next.js's use of webpack.

To Reproduce

Clone https://github.com/TidyIQ/nextjs-issue and run npm run dev.

Expected behavior

No issue

System information

  • OS: Windows 10
  • Version of Next.js: 8.1.1-canary.67

Most helpful comment

Update for modern Next.js (9.4+)

You can safely use fs within getStaticProps or getServerSideProps, no extra configuration required. Be sure you're referencing the variable in your data lifecycle so it's correctly tree shaken away.

You can use this tool to learn visually how it works!

If you're still building on a legacy Next.js version with getInitialProps, read below 👇


The provided code is not valid -- this file would never be available on the client side during rendering:

https://github.com/TidyIQ/nextjs-issue/blob/aef67b12d91d299d0978550005a40cbb34f74b71/pages/index.js#L5

Remember, you can only do FS-related operations while _on the server_. This means you cannot use fs while rendering.

If you use fs, be sure it's only within getInitialProps.

You may also need to create a next.config.js file with the following content to get the client bundle to build:

module.exports = {
  webpack: (config, { isServer }) => {
    // Fixes npm packages that depend on `fs` module
    if (!isServer) {
      config.node = {
        fs: 'empty'
      }
    }

    return config
  }
}

All 13 comments

Update for modern Next.js (9.4+)

You can safely use fs within getStaticProps or getServerSideProps, no extra configuration required. Be sure you're referencing the variable in your data lifecycle so it's correctly tree shaken away.

You can use this tool to learn visually how it works!

If you're still building on a legacy Next.js version with getInitialProps, read below 👇


The provided code is not valid -- this file would never be available on the client side during rendering:

https://github.com/TidyIQ/nextjs-issue/blob/aef67b12d91d299d0978550005a40cbb34f74b71/pages/index.js#L5

Remember, you can only do FS-related operations while _on the server_. This means you cannot use fs while rendering.

If you use fs, be sure it's only within getInitialProps.

You may also need to create a next.config.js file with the following content to get the client bundle to build:

module.exports = {
  webpack: (config, { isServer }) => {
    // Fixes npm packages that depend on `fs` module
    if (!isServer) {
      config.node = {
        fs: 'empty'
      }
    }

    return config
  }
}

I have the same problem on my local, practically vanilla install, however in the examples from nextjs this doesn not seem to be a problem
https://github.com/zeit/next.js/tree/5787cbd9de33ea9add7cadeb04689b0d4b02976d/examples/blog-starter

what makes it work there without modifying the config file?

Only use fs in getStaticProps / getServerSideProps as those are eliminated from the browser bundle.

I found out what the problem was. If I import a function that uses fs, but do not run/use the function inside getStaticProps, it will end up being included in the browser bundle. Once the function gets referenced inside getStaticProps it will stop appearing in the browser bundle.

I guess there is some hidden logic that removes imports used in getStaticProps but unused in main export. I spent a few hours debugging until I could reproduce, maybe worth having a sidenote somewhere in the docs :)

Isn't the hidden logic just webpack's tree shaking? Makes sense when you think of it, Next doesn't import getStaticProps in the browser bundle, so it removes the imported function used in it.

If you don't reference it anywhere, I guess webpack considers you imported it for side effects, so it still includes it in every bundle.

Isn't the hidden logic just webpack's tree shaking? Makes sense when you think of it, Next doesn't import getStaticProps in the browser bundle, so it removes the imported function used in it.

If you don't reference it anywhere, I guess webpack considers you imported it for side effects, so it still includes it in every bundle.

No, webpack tree shaking is not sophisticated enough to shake these exports in that way. Tree shaking getStaticProps / getServerSideProps / getStaticPaths is handled by this custom Babel plugin we created: https://github.com/vercel/next.js/blob/canary/packages/next/build/babel/plugins/next-ssg-transform.ts

Oh thanks for the pointer, looks like I overestimated webpack :)

Any reason this would be happening from _within_ getServerSideProps?

Hi all. Like @aloukissas I have the same issue when using dotenv within my index.js getStaticProps(). It gets solved when adding the next.config.js file as shown in @Timer initial comment.

Any clues why is this happening? I'm unsing Next.js v.9.4.0

Thanks!

I had this error while using fast-glob.

I used this great tool to understand the code that gets bundled in the client-side.

Turned out, I was importing a variable from a file that uses fast-glob which internally uses fs but I wasn't using the variable anywhere inside getStaticProps so the files imports fast-glob weren't getting eliminated.

An example:

mdxUtils.js

import glob from 'fast-glob'
import path from 'path'

export const BLOG_PATH = path.join(process.cwd(), 'posts')
export const blogFilePaths = glob.sync(`${BLOG_PATH}/blog/**/*.mdx`)

index.js

import { BLOG_PATH, blogFilePaths } from './mdxUtils'

export const getStaticProps = () => {
  const posts = blogFilePaths.map((filePath) => {
    ...
  }
  return { props: { posts } }
}

As you can see I am not using BLOG_PATH anywhere in index.js but still importing it. I am only using blogFilePaths so it gave me this error.

For more context → https://github.com/vercel/next.js/discussions/17138

Thanks @deadcoder0904 this is my code:

import Layout from '../components/template'
import Main from '../components/main'
import Menu from '../components/menu'
import 'dotenv/config'

export async function getStaticProps () {
  const avatarLocation = process.env.AVATAR_URL
  const avatarTitle = process.env.AVATAR_TITLE

  return {
    props: {
      avatarLocation,
      avatarTitle
    }
  }
}

export default function RenderMainPage ({ avatarLocation, avatarTitle }) {
  return (
    <Layout
      avatarURL={avatarLocation}
      topLeft={<Menu />}
      middle={<Main avatarURL={avatarLocation} avatarTitle={avatarTitle} />}
    />
  )
}

The tool you mention shows import 'dotenv/config' is included in the client code, and probably that is making the error appear. The thing is that I need it to read from the env variables.

Probably there's another better way to do it, I'm still learning Next.js :)

@ig-perez As of Next v9.4, they have a built-in way to load environment variables → https://nextjs.org/docs/basic-features/environment-variables

I suggest you read the docs to find the solution :)

That is awesome, I missed that part in the docs, thanks! I'll update my code 👍🏽

Was this page helpful?
0 / 5 - 0 ratings