Scaling a Payment Platform with Webpack Module Federation

How independent, dependency-free microfrontends let multiple teams ship a payment system in parallel — the wins, the traps, and the patterns that actually held up in production.

When a payment platform grows past a handful of teams, the monolithic frontend becomes the bottleneck. Every release is a coordination problem. Module Federation was how we broke that deadlock — but it came with sharp edges worth knowing before you adopt it.

Why Module Federation

The core idea: each microfrontend is built and deployed independently, then composed at runtime. A "host" app loads "remotes" over the network, so the checkout team can ship without waiting for the wallet team.

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

The shared config is the part people underestimate. Get singleton: true wrong and you ship two copies of React — hooks break in ways that are miserable to debug.

The three traps

  1. Version drift in shared deps. Pin shared singletons and fail loudly when versions mismatch, rather than silently loading a second copy.
  2. Runtime failures cascade. A remote that 404s shouldn't take down the host. Wrap every remote in an error boundary with a graceful fallback.
  3. Design-system duplication. Share the design system as a singleton remote too, or every team's bundle balloons.

What actually paid off

The measurable win wasn't performance — it was independent deploy cadence. Teams went from a shared weekly train to shipping several times a day. That's the number that matters to a business.

If you're evaluating microfrontends, don't do it for the tech. Do it when team coordination is your real bottleneck.