What Is Module Federation and How It Works
Module Federation is an architectural paradigm and build-tool feature—most notably introduced in Webpack 5—that allows multiple independent JavaScript builds to dynamically load code and share dependencies at runtime. This article explains what Module Federation is, the challenges it solves in distributed web applications like micro-frontends, and the exact runtime mechanisms it uses to prevent redundant dependency downloads across separate host and remote applications.
What Is Module Federation?
Traditionally, sharing code across multiple frontend applications required publishing shared libraries to a registry (like npm) and bundling them at build time into each host application. This approach tightly couples release cycles and often causes duplicate dependencies to be loaded by the browser.
Module Federation changes this by shifting code integration from build time to runtime. Under this model: * Host (Consumer): An application that initializes the page and dynamically imports code from other builds. * Remote (Producer): An independently built and deployed application that exposes specific components, utilities, or state to outside consumers. * Bidirectional Hosts: Applications that both consume remotes and expose modules to other applications.
How Module Federation Shares Dependencies
When multiple distributed micro-frontends run in a single browser window, loading identical third-party libraries (such as React, Vue, or Lodash) for each application wastes bandwidth and can cause runtime conflicts. Module Federation solves this via its runtime dependency-sharing mechanism.
1. The shared
Configuration
In the configuration file (e.g., webpack.config.js),
developers define shared dependencies inside the
ModuleFederationPlugin:
new ModuleFederationPlugin({
name: 'app_host',
remotes: {
app_remote: 'app_remote@https://example.com/remoteEntry.js',
},
shared: {
react: {
singleton: true,
requiredVersion: '^18.2.0',
},
'react-dom': {
singleton: true,
requiredVersion: '^18.2.0',
},
lodash: {
singleton: false,
},
},
});2. The Shared Scope
When an application boots up, it initializes a global object called the Shared Scope. This acts as an in-memory registry of all dependencies that any loaded module can provide or consume.
Before executing application code, the initialization phase: 1.
Registers the host’s dependencies and their semantic versions (SemVer)
into the shared scope. 2. Fetches the remote entry manifest
(remoteEntry.js) of any declared remotes. 3. Registers the
remote’s declared dependencies and versions into the same shared
scope.
3. Semantic Version Negotiation
When a component inside a host or remote requests a shared package, Module Federation resolves the dependency dynamically:
- Version Matching: The runtime compares available
versions in the shared scope against the
requiredVersionrange defined by the requesting module. - Highest Compatible Version: If multiple compatible versions exist, the runtime provides the highest compatible version available, downloading it only once.
- Fallback Loading: If a remote requires a version
incompatible with what the host initialized, and
singletonis not set totrue, the remote will automatically download its own compatible version in isolation.
4. Singleton Enforcement
Certain libraries (like React, React DOM, or state management stores) must only have a single instance instantiated in memory to avoid broken context and hook errors.
Setting singleton: true guarantees that only one
instance of the library is ever loaded. If version mismatches occur
under singleton mode, the runtime logs a console warning and uses the
highest compatible version rather than instantiating a duplicate
copy.
Key Benefits of Shared Dependencies
- Reduced Bundle Size: Eliminates duplicate copies of shared libraries, lowering total network payload and parse time.
- Independent Deployments: Teams can deploy updates to remotes without forcing the host application to rebuild or redeploy.
- Unified State and Contexts: Singleton enforcement enables seamless sharing of UI libraries and global contexts across distributed codebases.