Skip to content

SYSTEM Cited by 1 source

Webpack Module Federation

What it is

Webpack Module Federation is a feature of the Webpack bundler that lets multiple independently-built-and-deployed JavaScript bundles share modules at runtime, without the host rebuilding or statically linking the remote.

Introduced in Webpack 5 (2020), Module Federation supplies the runtime composition primitive that most contemporary micro-frontend architectures build on when they want per-team independent deploys of frontend bundles plus shared React instances across the page.

See the Webpack docs and the Zalando Logistics portal writeup (sources/2024-10-16-zalando-building-a-modular-portal-with-webpack-module-federation).

Runtime shape

Three roles:

  • Host — the shell bundle that consumes remotes. Loads a remote's entry file (RemoteEntry.js) at runtime and dynamically imports exposed modules.
  • Remote — a bundle built independently that exposes specific modules (components, utilities, routes) for other bundles to consume. Publishes a RemoteEntry.js manifest at a known URL.
  • Bidirectional — a bundle can be both host and remote simultaneously (consume some modules, expose others).

Two kinds of contracts:

  • exposes — a remote declares what modules it publishes ("./Button": "./src/Button"). The host imports by remote name and exposed key.
  • shared — both host and remote declare shared libraries that must be resolved to a single instance at runtime (e.g. react, react-dom). Webpack's runtime picks a compatible version; marking a shared library singleton: true forces a single instance across the entire page — see concepts/shared-singleton-dependency.

What it gives you

  • Runtime code sharing — no rebuild of the host when a remote ships a new version; the next page load picks up the change (concepts/runtime-code-sharing).
  • Shared dependency deduplication — React, React-DOM, lodash, etc. load once and are reused across host and all remotes, avoiding multi-copy-React bugs and cutting bundle size.
  • Independent team deploys — each remote's CI/CD owns its own bundle URL; the host only needs the URL, not the source.
  • Per-route lazy loading — remotes can be fetched only when the user navigates to their section, keeping the shell's initial payload small.

What it doesn't give you

  • Auth / authorisation. Module Federation is purely a bundle-loading mechanism; cross-remote authentication, permission checks, and backend-call gating need a separate layer (see patterns/centralised-backend-proxy-for-micro-frontends for Zalando's approach).
  • A communication contract between remotes. Remotes can import each other's exposes, but for loose coupling teams still need a governed API — e.g. a prop passed from host to remote, an event bus, or a typed context (see patterns/host-shell-prop-api-for-remotes).
  • Version-skew resolution across independent deploys. If the host upgrades React while a remote still bundles an incompatible version, singleton: true can produce runtime errors. Teams must align major versions during development.
  • Discovery. A host still needs to know which remotes to load, from which URLs, with which scopes. That's why Module-Federation deployments often sit behind a manifest-driven loading layer (see patterns/manifest-driven-micro-frontend-loading).

Canonical configuration shape

Abstracted from the Webpack docs + the Zalando Logistics portal post:

// Host webpack.config.js
new ModuleFederationPlugin({
  name: "portal",
  remotes: {
    // loaded at runtime from URLs in the portal manifest
    lastMile: "lastMile@/last-mile/remoteEntry.js",
  },
  shared: {
    react: { singleton: true, eager: true },
    "react-dom": { singleton: true, eager: true },
  },
});

// Remote webpack.config.js
new ModuleFederationPlugin({
  name: "lastMile",
  filename: "remoteEntry.js",
  exposes: { "./App": "./src/App" },
  shared: {
    react: { singleton: true },
    "react-dom": { singleton: true },
  },
});

The singleton: true on both sides is the load-bearing property for a shared React — without it, host and remote each load their own React and hooks (useState, context) fail at runtime because the two React instances don't share their fiber tree.

Seen in

  • sources/2024-10-16-zalando-building-a-modular-portal-with-webpack-module-federation — canonical wiki deployment: Zalando's Logistics / Transport internal portal uses Module Federation to compose 11 applications built by 4 teams into a single authenticated portal. Host loads each remote's RemoteEntry.js via a server-side /applications + per-app manifest.json flow; shared React / React-DOM as singletons; prop-based shell API for cross-remote communication.
Last updated · 501 distilled / 1,218 read