Webpack Module Not Found (tested)

Module not found: Error: Can't resolve 'X' in 'Y' is webpack's error for an import it cannot turn into a file. We built a minimal webpack 5 project with no loaders and reproduced four distinct causes, then show the exact error text and the one-line fix for each.

1. The base error

webpack throws this when it finishes searching every place an import could resolve to and finds nothing. The message always has the same shape:

ERROR in ./src/index.js 1:0-37
Module not found: Error: Can't resolve 'totally-fake-pkg-xyz' in '/tmp/webpack-notfound-guide/src'

Below it, webpack 5 prints the full resolve trace: every extension and every candidate path it tried. That trace is verbose but tells you exactly what webpack thinks the module should be called and where it looked.

2. Cause 1: the package isn't installed

We imported a package that was never added to node_modules:

import x from 'totally-fake-pkg-xyz';

Exact output:

ERROR in ./src/index.js 1:0-37
Module not found: Error: Can't resolve 'totally-fake-pkg-xyz' in '/tmp/webpack-notfound-guide/src'
resolve 'totally-fake-pkg-xyz' in '/tmp/webpack-notfound-guide/src'
  ...
      looking for modules in /tmp/webpack-notfound-guide/node_modules
        ...
          /tmp/webpack-notfound-guide/node_modules/totally-fake-pkg-xyz doesn't exist
      /tmp/node_modules doesn't exist or is not a directory
      /node_modules doesn't exist or is not a directory

The giveaway is looking for modules in .../node_modules followed by every parent node_modules up to filesystem root, all "doesn't exist". Fix: npm i package-name (check the spelling and that it's the right package name on npm first).

3. Cause 2: a typo'd relative import

The file was src/Button.js; the import said ./Buton:

import Button from './Buton';

Exact output:

ERROR in ./src/index.js 1:0-29
Module not found: Error: Can't resolve './Buton' in '/tmp/webpack-notfound-guide/src'
Did you mean './Button.js'?
'Button.js' is the closest name in that directory. It differs from the request by 1 character, ignoring case and file extension.
resolve './Buton' in '/tmp/webpack-notfound-guide/src'
  ...

Webpack 5.111 does add a "Did you mean" suggestion when a close filename exists in the same directory, with the edit distance it used to decide. It only suggests from files actually present, so if the real file is in a different folder you still get no hint. Fix: correct the path or extension.

4. Cause 3: no loader for the file type (not always "Can't resolve")

With zero loaders configured, importing a .css file actually worked on this version:

import './styles.css';
asset bundle.css 161 bytes [emitted] (name: main)
webpack 5.111.1 compiled successfully

webpack 5.111 has built-in experimental CSS support (asset type css) that activates automatically for .css files even with no module.rules at all and no css-loader installed. Don't assume you need a loader for CSS on current webpack — test your version first.

.svg is not handled the same way. Importing one with zero rules gave a different error, not "Can't resolve":

ERROR in ./src/icon.svg 1:0
Module parse failed: Unexpected token (1:0)
File was parsed as module type 'javascript/auto'.
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> 1 | <svg></svg>
    | ^

webpack found the file fine (resolution succeeded) and only failed when it tried to parse SVG markup as JavaScript. The fix needs no third-party loader; webpack 5's built-in asset modules cover this:

module: { rules: [{ test: /\.svg$/, type: 'asset/resource' }] }

Adding that rule made the same import compile cleanly and emit the SVG as a separate file.

5. Cause 4: resolve.extensions or resolve.alias misconfigured

We set resolve.extensions to only ['.json'], overwriting webpack's default list instead of extending it, then imported an existing file by its bare name:

import Button from './Button';  // Button.js exists

Exact output, with the file physically present on disk:

ERROR in ./src/index.js 1:0-30
Module not found: Error: Can't resolve './Button' in '/tmp/webpack-notfound-guide/src'
resolve './Button' in '/tmp/webpack-notfound-guide/src'
  ...
    using description file: .../package.json (relative path: ./src/Button)
      no extension
        /tmp/webpack-notfound-guide/src/Button doesn't exist
      .json
        /tmp/webpack-notfound-guide/src/Button.json doesn't exist
      as directory
        /tmp/webpack-notfound-guide/src/Button doesn't exist

The trace shows webpack only tried no extension and .json — it never tried .js, because the config replaced the whole list. Fix: extend instead of replace, using webpack 5's '...' token to keep the defaults:

resolve: { extensions: ['.json', '...'] }

With that change the same import resolved to Button.js and the build succeeded. The same replace-vs-extend mistake with resolve.alias pointing a prefix at the wrong directory produces the identical "Can't resolve" message for imports that look correct in the source.

6. Checklist

Frequently asked questions

What does "Module not found: Error: Can't resolve 'X' in 'Y'" mean in webpack?

Webpack searched every path and extension it knows for the import 'X' starting from directory 'Y' and found no matching file or package. The full trace printed under the error lists exactly where it looked.

Why didn't installing the package fix the error?

Check the exact name and casing against npm, that it's listed in package.json's dependencies, and that node_modules actually contains it (run npm ls <package>). A stale node_modules or a typo in the package name both produce the same error we measured.

Does webpack suggest the correct filename on a typo?

Sometimes. In our test, importing './Buton' instead of './Button.js' produced a "Did you mean './Button.js'?" line, because webpack 5.111 checks for similarly-named files in the same directory. It won't suggest files in other folders.

Why did my .css import work with no loader but .svg didn't?

On webpack 5.111 we measured, .css has built-in experimental support and compiles without css-loader. .svg has no such built-in handling for raw file content; it gets parsed as JavaScript and fails differently ("Module parse failed", not "Can't resolve"). Add a rule with type: 'asset/resource' for .svg and similar binary/text assets.

I set resolve.extensions and now imports without an extension break. Why?

resolve.extensions replaces webpack's default list entirely rather than adding to it. If you set it to ['.json'], webpack stops trying .js. We confirmed the fix: add the '...' token, e.g. extensions: ['.json', '...'], to keep the defaults alongside your addition.

Written with AI assistance. Measured on 2026-10-02 with Node.js 24.21.0, webpack 5.111.1 and webpack-cli 7.2.3, using `npx webpack build` (mode: development) against a bare config with zero loaders unless noted. PlainHeaders is our extension; webpack is free and open source.