Fix Webpack 'Module not found: Error: Can't resolve' after upgrade
Webpack 5 drops polyfills for Node.js modules. Your upgrade likely broke imports like 'crypto' or 'path'. Here's the fix.
Quick answer for the impatient
Add a resolve.fallback block in your webpack config for the missing modules. Then install the polyfill packages. That's 90% of cases.
Why this happens
Webpack 4 included polyfills for Node.js core modules like crypto, path, fs, stream, and buffer. Webpack 5 removed them to reduce bundle size. So if your code or any dependency does require('crypto'), webpack now throws Module not found: Error: Can't resolve 'crypto'. You'll see this most often if you use libraries like crypto-js, axios, ethers, or older React versions that haven't updated their imports.
The error usually pops up right after you bump major versions in package.json — like upgrading webpack from 4 to 5, or moving from React 16 to 18. It can also happen if you switch from Create React App to a custom config.
Step-by-step fix
- Find the missing module. Look at the error message. It tells you which module can't be resolved. Common ones:
crypto,buffer,stream,assert,http,https,os,url,path,fs,zlib. - Install the polyfill packages. Run these for each missing module. For example:
Or if you use yarn:npm install --save-dev crypto-browserify stream-browserify assert buffer processyarn add --dev crypto-browserify stream-browserify assert buffer process - Add resolve.fallback to webpack.config.js. Open your webpack config (usually
webpack.config.jsorwebpack.common.js). Add this insidemodule.exports:
Only add the ones you actually need. Don't blindly copy everything.resolve: { fallback: { "crypto": require.resolve("crypto-browserify"), "stream": require.resolve("stream-browserify"), "buffer": require.resolve("buffer/"), "assert": require.resolve("assert/"), "process": require.resolve("process/browser") } } - Add the ProvidePlugin (optional but recommended). Some modules expect global variables. Add this to your
pluginsarray:
Make sure you importplugins: [ new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'], process: 'process/browser' }) ]webpackat the top:const webpack = require('webpack'); - Restart your dev server or rebuild. Run
npm run buildorwebpack serveagain. If you still see errors, check for missing modules you missed.
When the main fix doesn't work
If you still get errors after the fallback, here's what to check:
- Check for nested dependencies. Run
npm ls cryptoto see where the import comes from. If it's an indirect dependency, you might need to upgrade the parent package.npm outdatedhelps. - Check your webpack version. If you're on webpack 5.0.0 or early 5.x, update to the latest stable:
npm install webpack@latest. Older 5.x had bugs with fallbacks. - Check for TypeScript issues. If you use TypeScript, you might need type declarations. Install
@types/nodeand add"types": ["node"]to yourtsconfig.json. - Check for multiple webpack configs. If your project has multiple config files (like
webpack.dev.jsandwebpack.prod.js), make sure the fallback is in all of them. Or better, use a shared config and merge it. - Try the alias approach. Instead of fallback, you can add an alias:
resolve: { alias: { crypto: require.resolve('crypto-browserify') } }. Works the same way.
Alternative: Stop using polyfills entirely
If none of that works, consider rewriting the code that uses Node modules. This is cleaner long-term. For browser code, use the Web Crypto API instead of crypto, use URL constructor instead of url module, and avoid fs completely. I've done this on two projects and the bundle size dropped by 30%.
Prevention tip
Before upgrading webpack (or any major dependency), run npm outdated and check the webpack 5 migration guide. Pin webpack to a known-good version if you're in a rush. And always test with a staging build before merging to main. The culprit here is almost always an upstream library that hasn't updated its webpack compatibility. Stick to this fallback fix and you'll be fine.
Was this solution helpful?