Module Federation Cheat Sheet
Module Federation lets webpack builds share runtime modules: a host consumes exposed modules from remotes loaded at runtime via remoteEntry.js.
How to use this Module Federation cheat sheet The host webpack config lists remotes by name and URL; remotes expose modules in federation config. shared declares singleton dependencies (react, react-dom) with requiredVersion to dedupe across apps.
eager: true bundles shared deps in the entry chunk (host often eager for React); eager: false loads shared async. Version mismatches fall back or warn depending on singleton and strictVersion settings.
Quick Module Federation example // webpack.config.js — remote
new ModuleFederationPlugin({
name: 'shop',
filename: 'remoteEntry.js',
exposes: { './ProductPage': './src/ProductPage' },
shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
});
// host
new ModuleFederationPlugin({
name: 'shell',
remotes: { shop: 'shop@https://cdn.example/shop/remoteEntry.js' },
shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true } },
}); Host & Remote Roles Role Example Notes Host (shell) Consumes remote modules Owns page shell and routing Remote Exposes modules via remoteEntry.js Deployed independently name name: "shop" Unique federation scope filename remoteEntry.js Entry script host loads at runtime remotes shop@https://.../remoteEntry.js URL must be reachable from browser exposes "./Button": "./src/Button" Public API surface of remote Dynamic remote import("shop/ProductPage") Lazy load federated module Runtime plugin Module Federation 2.0 enhanced API Advanced manifest and DTS sharing
Shared Dependencies Option Example Notes singleton react: { singleton: true } One instance across host and remotes requiredVersion requiredVersion: "^18.2.0" Semver range for compatibility check strictVersion strictVersion: true Fail load on mismatch instead of fallback eager eager: true Include in initial bundle; no async shared chunk import import: "react" Override shared module path shareScope shareScope: "default" Isolate shared sets per scope sharedStrategy loaded-first vs version-first MF2 runtime negotiation Peer deps Align package.json peers across repos Prevent duplicate React
Versioning & Deployment Practice Example Notes Independent deploy Remote ships without host rebuild Host resolves remoteEntry URL at runtime Version in URL /shop/v2/remoteEntry.js Pin host to known remote version Latest alias /shop/latest/remoteEntry.js Convenience; risky without integration tests Fallback remote Try v2 then v1 remote URL Graceful degradation on failed load CI contract tests Host imports remote in e2e Catch breaking expose path changes TypeScript Generate @types remotes or DTS federation Typed federated imports SSR Node federation plugins Separate from browser remoteEntry flow CDN cache Cache remoteEntry briefly; hash chunks long Balance deploy speed vs stale entry
Eager vs Async Loading Pattern Example When Eager shared on host react: { singleton: true, eager: true } Host provides React immediately Async shared eager: false (default) Smaller initial host bundle Eager remote expose Rare; usually lazy import Only for critical path widgets Lazy route React.lazy(() => import("shop/ProductPage")) Code-split federated pages Prefetch remoteEntry <link rel="prefetch" href="remoteEntry.js"> Warm connection before navigate Error boundary Catch failed remote load Show retry when CDN or remote down publicPath output.publicPath: "auto" Correct chunk URLs for remotes Module type output.module + experiments.outputModule ESM federation in webpack 5
Lazy federated route in React const ProductPage = React.lazy(() => import('shop/ProductPage'));
function Routes() {
return (
<Suspense fallback={<Spinner />}>
<Route path="/products" element={<ProductPage />} />
</Suspense>
);
} Wrap federated components in Suspense; network load happens on first navigation.
Dynamic remote at runtime const remoteUrl = window.__REMOTES__.shop;
await __webpack_init_sharing__('default');
const container = await import(/* webpackIgnore: true */ remoteUrl);
await container.init(__webpack_share_scopes__.default);
const factory = await container.get('./ProductPage');
const Module = factory(); Advanced pattern for runtime-configured remote URLs (micro-frontend shell).
Nx module federation project.json stub {
"targets": {
"serve": { "options": { "port": 4201 } }
},
"tags": ["scope:shop", "type:remote"]
} Monorepo tools generate federation config; keep remote serve ports documented for local dev.
Common mistakes Mismatching React versions across host and remotes with singleton disabled. Hard-coding remoteEntry URL without environment-specific config for dev/staging/prod. Exposing entire app root instead of narrow module APIs, coupling host to remote internals. Caching remoteEntry.js aggressively while changing exposed module paths without coordination. Key takeaways Host consumes remotes; remotes expose modules via remoteEntry.js. shared + singleton dedupes react and other libraries at runtime. eager loads shared in entry; lazy import defers federated UI until needed. Version remote URLs and run contract tests before promoting remote deploys.
Pro Tip
Treat exposed module paths as public API—semver them and never rename without a deprecation window and host compatibility shim.
Common Federation Mistakes Go to next item