You're building a host app that loads a remote component. The remote's webpack config declares a shared dependency like React with singleton: true. The moment you load the remote, the console throws Shared module not found for version .... This usually shows up when the host and remote have different versions of the same library, and Webpack can't decide which one to use.
What's actually happening here
Webpack's Module Federation has a shared-scope resolution algorithm. When a remote declares that it wants to share a module, Webpack checks the host's shared-scope to see if there's a version that satisfies the remote's required version range. If you've set singleton: true, Webpack tries to force a single instance, but it still validates the version range. If the host provides a version that doesn't match the remote's range, or if the host simply doesn't provide that module at all, you get the "Shared module not found" error.
In my experience, this error pops up most often when the remote doesn't list the shared module in its shared config, but the remote's code still imports it. Wait—that's another scenario. The one you're hitting is when the remote declares a shared module with a strict version like "react": { "requiredVersion": "^17.0.0" }, and the host is running React 18. The range ^17.0.0 doesn't include 18, so Webpack says "nope, can't share that." But because singleton: true is set, it won't just load its own copy—it insists on using the host's version, which doesn't match. Deadlock.
The fix is straightforward: align your version ranges, or let Webpack fall back to the remote's own copy when versions don't match.
The fix, step by step
- Decide on a singletons list. Libraries like React, ReactDOM, and any state management (Redux, Zustand) must be singletons across the app. If you try to share them as non-singletons, you'll get double instances and, in React's case, the dreaded invalid hook call. So keep
singleton: truefor those. - Check the actual version ranges. On both the host and the remote, open the
sharedsection of their ModuleFederationPlugin config. Look at whatrequiredVersionyou've put there. If you wrote"react": "^17.0.0"but your project uses React 18, that's the problem. Either bump the range to^18.0.0or removerequiredVersionentirely—Webpack will then use whatever version is available. - If you can't unify versions, allow fallback. Sometimes you genuinely need different versions for the host and remote. Say the remote is a legacy widget that only works with React 16, but the host is on 18. In that case, don't force a singleton for that library. Instead, remove
singletonor set it tofalse, and let Webpack load two separate copies. Yes, it's heavier, but it beats a broken UI. - For libraries that must be singletons and must match, do a version alignment. Update both apps to use the same major version. For React, that's usually React 18. Then set
requiredVersionto a range that covers your version, like"^18.2.0". Or just omitrequiredVersion—Webpack will use the built-in version detection from the package.json. - When you omit
requiredVersion, Webpack reads the version from the package.json of the consuming app. That's the version it uses for the range check. So make sure the package.json on each side reflects what's actually installed. I've seen cases where the lockfile had one version but package.json said another, and that caused a mismatch. - Re-run the build. This error comes from build-time resolution, not runtime. So after changing the config, rebuild both the remote and the host. If you're using webpack-dev-server, restart it too.
What if it still fails?
Here's where it gets sneaky. The error often appears not on the host's initial load, but when the remote tries to load its own dependencies. Open the browser's network tab and look at the federated files being loaded. Each remote exposes a file like remoteEntry.js. Check the console for the exact version string mentioned in the error. It'll say something like Shared module not found for version ^17.0.0. That tells you which library and which range is failing.
If you've aligned versions and still see the error, check if the remote is using a different build tool or a different version of Webpack. Module Federation is supported from Webpack 5.0, but there were bugs in early 5.x.x releases. Update to at least Webpack 5.74.0—I've seen version detection quirks fixed over time.
Another gotcha: if you're using eager consumption. When a shared module is marked eager: true, Webpack loads it immediately, and it might not be placed in the shared scope properly. Remove eager unless you know exactly why you added it. In one project, I added eager to speed up first load, but it broke sharing because the eager module was initialized before the shared scope was set up.
Finally, check if you're importing the shared library in the remote's entry point. If the remote's entry file does import React from 'react' at the top level, that can force Webpack to resolve it before the federation runtime is ready. The recommended pattern is to only import the shared library inside the components that use it, not at the entry. This is a known pitfall with the index.js of the remote.
If you've done all that and it still complains, then take a hard look at your shared object's keys. They must match the module specifier used in the import statements. A mismatch like "react-dom" vs "react-dom/client" will cause a miss. In React 18, you might import from react-dom/client in one app and from react-dom in another—those are treated as different modules. You'd need to share both keys if you use both entry points.
I'll be blunt: the cleanest setup I've used is to define a shared object like this on both host and remote:
shared: {
react: { singleton: true, requiredVersion: '^18.2.0' },
'react-dom': { singleton: true, requiredVersion: '^18.2.0' },
'react-dom/client': { singleton: true, requiredVersion: '^18.2.0' }
}
That covers both import styles. And yes, you need to install the same React version in both apps. If you can't, then you're back to the non-singleton approach. That's a trade-off, and you have to own it.
The underlying cause is always the same: Webpack's shared scope is a contract between host and remote. When one side violates the contract—wrong version, missing key, or bad timing—you get this error. Fix the contract, and the error goes away.