Back to the blog
Webpack· Aug 5, 2026· 9 min read

Module Federation in production: sharing code across independently deployed apps

How Webpack 5's Module Federation actually works under the hood, a working host/remote config, and the version-mismatch failure modes that only show up after you ship.

#webpack#module-federation#micro-frontends#architecture

Module Federation shipped in Webpack 5 and quietly solved a problem teams had been hacking around for years: loading code from one independently built and deployed application into another, at runtime, without either app knowing the other's internals at build time. It's the enabling technology behind most production micro-frontend architectures that don't rely on iframes.

The mental model

A 'remote' app exposes a JS module - a component, a hook, a whole page - as a named entry in its build output. A 'host' app declares that remote as a dependency and imports from it using a dynamic import that Webpack resolves over the network at runtime, not at build time. Both apps ship independently; the wiring happens in the browser.

// remote app's webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'checkout',
      filename: 'remoteEntry.js',
      exposes: {
        './CheckoutForm': './src/CheckoutForm',
      },
      shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
    }),
  ],
};
// host app's webpack.config.js
new ModuleFederationPlugin({
  name: 'shell',
  remotes: {
    checkout: 'checkout@https://checkout.example.com/remoteEntry.js',
  },
  shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
});

// host app's code
const CheckoutForm = React.lazy(() => import('checkout/CheckoutForm'));

'singleton: true' is not optional for React

Without `singleton: true` on shared dependencies, host and remote can each bundle their own copy of React, and you get the infamous 'Invalid hook call' error - not from a bug in your code, but from two React instances existing in the same page with incompatible internal state. Singleton sharing forces every federated module to use the host's single React instance, at the cost of the host and remote needing compatible (not necessarily identical) major versions.

The failure mode nobody warns you about: silent version drift

Module Federation has no build-time type checking across the boundary - a remote can change a prop's shape, deploy independently, and the host won't know until a user hits the broken path in production. We treat every exposed module's public interface as a versioned contract: a shared `@org/checkout-contract` TypeScript package the host imports for types, with the remote's CI failing if it drifts from that contract without a version bump.

When Module Federation is the wrong tool

  • A single team, single deploy cadence, single repo - you want a monorepo with regular imports and shared build tooling, not runtime federation.
  • Hard real-time consistency requirements across the federated boundary - independent deploys mean host and remote are never guaranteed to be on compatible versions at the same instant.
  • Small teams without the operational maturity to version and monitor cross-app contracts - the failure modes are invisible until a user hits them, and debugging spans two codebases and two deploy pipelines.
Module Federation trades build-time safety for deploy-time independence. Only take that trade if independent deploys are a real organizational need, not a hypothetical one.

Written by Appesto Engineering.