Webpack 5 Module Federation: Runtime Code Sharing for Micro‑Frontends
Learn how Webpack 5’s Module Federation lets you share code across micro‑frontends at runtime. Walk through a host/remote setup, see a live Button example, and weigh the trade‑offs before you deploy.
10 Oct 2026, 19:45 UTC

Why Code Sharing Matters in Modern Frontends
When a single application grows into several teams, bundling everything into one monolith becomes a maintenance nightmare. Module Federation lets each team ship its own Webpack bundle that can be loaded on demand by a host application. The result is smaller initial payloads, independent deployment cycles, and the ability to upgrade parts of the UI without touching the whole codebase.
What Module Federation Actually Does
Module Federation is a Webpack 5 feature that exposes modules from one bundle (the remote) and consumes them from another (the host) via a shared runtime registry. At load time the host asks the remote for a named module; the remote registers that module on the global window object, and the host resolves it through import(). Because the registry lives in the browser, the host can lazily fetch and execute modules from any remote, even if the remote is served from a different domain.
Key Configuration Pieces
name– unique identifier for a bundle.remotes– mapping of remote names to URLs.exposes– modules a remote makes available.shared– libraries that should be singletons across all bundles.
Concrete Example: A Host & a Remote Exposing a Button
- Remote Project (Button)
// webpack.config.js const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); module.exports = { mode: 'development', output: { publicPath: 'http://localhost:8081/', }, plugins: [ new ModuleFederationPlugin({ name: 'buttonRemote', filename: 'remoteEntry.js', exposes: { './Button': './src/Button.jsx', }, shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true }, }, }), ], };Run the remote dev server:
npm run start:remote(assumeswebpack-dev-serverlistening onlocalhost:8081). - Host Project (App)
// webpack.config.js const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); module.exports = { mode: 'development', output: { publicPath: 'http://localhost:8080/', }, plugins: [ new ModuleFederationPlugin({ name: 'hostApp', remotes: { buttonRemote: 'buttonRemote@http://localhost:8081/remoteEntry.js', }, shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true }, }, }), ], };In the host’s code, consume the remote module lazily:
import React, { Suspense } from 'react'; const RemoteButton = React.lazy(() => import('buttonRemote/Button')); function App() { return ( <div> <h1>Host Application</h1> <Suspense fallback="Loading button..."> <RemoteButton /> </Suspense> </div> ); } export default App; - Verification Steps
- Start both dev servers.
- Navigate to
http://localhost:8080– the button should appear after a brief load. - Open Chrome DevTools Network panel; you should see a request for
remoteEntry.jsand theButtonchunk only when the component mounts. - Check the console for any React warnings; only one instance of React should be loaded.
Trade‑Offs and Practical Limitations
- Version Compatibility – If the remote updates a shared library (e.g., React 17 → 18), the host must rebuild to match the version constraints. Mismatched versions can cause rendering glitches or runtime errors.
- Network Latency – The host’s first paint may be delayed by the remote’s fetch. Use CDN caching and prefetch hints to mitigate.
- Debugging Complexity – Errors originate in separate bundles. Ensure source maps are enabled for each remote to trace stack traces back to the original source.
- Deployment Coordination – The host must know the remote’s URL. In production, environment variables or a manifest service can keep these mappings up to date.
Actionable Checklist for Engineers
- Decide which parts of your app should be isolated as remotes.
- Add
ModuleFederationPluginto each Webpack config, definingname,exposes, andshared. - In the host, declare
remoteswith the remote’s URL. - Consume remote modules with
React.lazyor dynamicimport()for lazy loading. - Configure source maps and CDN caching for production.
- Set up automated integration tests that spin up both host and remote servers to catch version mismatches early.
With these steps, you can start leveraging Module Federation to build maintainable, independently deployable micro‑frontends while keeping bundle sizes lean and runtime performance high.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.