skip to content

Module Federation

The Webpack and Vite mechanism for loading code from another independently built app at runtime: hosts, remotes, exposes, dynamic remotes and the shared-module container protocol. It is the concrete answer to how microfrontends load each other without a rebuild.

part ofSoftware design & architectureoverview, primer and where to startread it →
on this pageshow

questions

6

In a microfrontend architecture using Webpack Module Federation, what is the difference between a 'host' application and a 'remote' application, and how do they connect at runtime?

level: juniorimportance: must knowfreq 55%

answer

  1. remote exposes, host imports
  2. remoteEntry.js = container
  3. get()/init() protocol
  4. any app can be both host and remote
  5. runtime coupling, not build-time

basics

~20 s

A host is the app that loads pieces from other apps; a remote is the app that shares its pieces. Webpack lets the host fetch and run the remote's code straight from the browser, without both being built together.

solid answer

~40 s

Module Federation lets independently built and deployed JavaScript bundles share code at runtime instead of build time. A 'remote' app exposes specific modules (components, pages, utils) through a small manifest bundle (remoteEntry.js) listing what's available and how to fetch it. A 'host' app declares that remote as a dependency (by name and URL) and can then import() the exposed module as if local, even though it lives in a separately deployed app. The browser loads the host's bundle first, then on demand fetches the remote's container script, which exposes get(module) and init(shareScope) functions the host calls to retrieve the module and negotiate shared dependencies. Any app can be both host and remote simultaneously, enabling nested composition across teams without a monorepo build.

go deeper

for a junior

Should be able to explain, in plain language, that a host loads pieces from a remote at runtime and that they're built and deployed separately.

for a middle

Should name remoteEntry.js as the connecting piece and know that both host and remote are set up via ModuleFederationPlugin config.

for a senior

Should describe the get/init container protocol mechanism and compare Module Federation against iframes and monorepo build-time composition as alternative solutions to the same organizational problem.

for a principal

Should discuss the organizational trade-offs of adopting Module Federation at scale — team autonomy versus runtime coupling, deployment independence versus a wider failure surface — and when this architecture is and isn't worth its operational cost.

## The vocabulary Module Federation is a Webpack 5 (and now Vite-ecosystem) capability that lets multiple, independently built and independently deployed JavaScript bundles share code with each other at runtime, through the browser, rather than at build time through a shared repository or npm package. The core vocabulary is 'host' and 'remote.' - A **host** is the application the user's browser loads first — typically a shell or container app that owns the page's routing, top-level layout, and authentication. - A **remote** is a separately built and separately deployed application that exposes some of its internal modules (a component, a page, a utility function) for other applications to consume. Critically, any single application can play both roles at once: a 'team B' app can be a remote to the shell while itself acting as a host to a smaller widget owned by 'team C.' This is what makes Module Federation a true architecture for horizontally scaling frontend ownership across teams, rather than just a code-splitting trick. ## How the connection is made Mechanically, the connection happens through a small, auto-generated file called the container, conventionally named `remoteEntry.js`. When a remote app is built with the ModuleFederationPlugin's `exposes` option, Webpack emits this container alongside the remote's normal bundles. The container is a tiny piece of JavaScript that, once loaded into any page's global scope, registers itself under the remote's configured name and exposes two functions the specification calls the container protocol: - `init(shareScope)`, which lets the container register itself into a shared dependency scope so it can, for example, reuse the host's already-loaded copy of React instead of shipping its own. - `get(moduleName)`, an async function that returns the actual exposed module on demand. On the host side, a `remotes` entry in its own `ModuleFederationPlugin` config tells Webpack 'there is a remote called catalog, reachable at this URL for its remoteEntry.js.' When host code executes `import('catalog/ProductList')`, Webpack's runtime — not the bundler at build time — fetches remoteEntry.js over the network if it hasn't been fetched already, calls init then get, and resolves the import with the live module. Nothing about the remote's internal code needs to exist in the host's repository or build pipeline at all; the two apps can use completely different CI/CD pipelines, deploy on independent schedules, and even be owned by different teams with no coordinated release train. ## Why it exists The reason this exists is organizational as much as technical. Before Module Federation, teams splitting a large frontend into independently deployable pieces had few good options: | Approach | What it buys | Where it falls short | |---|---|---| | iframes | heavy isolation | poor UX — no shared routing, styling, or state, and painful cross-frame communication | | build-time monorepo composition | fast and safe | forces a single release train and a single Webpack config, defeating the purpose of team autonomy | | hand-rolled script-tag loading of UMD bundles | works | reinvents dependency sharing and versioning badly | Module Federation gives near-native integration — remote components render as first-class components inside the host's tree, sharing the same DOM, router, and even framework runtime — while still letting each remote be built, versioned, and deployed completely independently, often on its own CDN path, with its own on-call team. ## The trade-off The trade-off is that this convenience is paid for with **runtime coupling** and a wider failure surface than either extreme. - Because the host fetches `remoteEntry.js` live in the user's browser, the host now has an implicit runtime dependency on the remote's availability, its CDN, its CORS configuration, and its compatibility with whatever shared library versions the host has already loaded. A remote that renders fine in isolation can throw at runtime in the host if it assumes a newer framework version than the host's singleton copy provides. - Debugging is also harder: stack traces cross the boundary between two bundles compiled independently, source maps must be shipped and correctly resolved for each remote, and a bug might only reproduce in the specific host+remote+shared-version combination running in production, not in either app's own dev environment. ## Where it shows up A realistic scenario: an e-commerce shell app owned by a platform team hosts a checkout remote owned by a payments team and a catalog remote owned by a merchandising team. Each team ships to production multiple times a day without touching the shell's repository or waiting on the platform team's release calendar — the shell only needs the remote's stable exposed URL and a compatible shared-dependency contract, and every deploy of checkout is instantly live to the user the next time the shell resolves that remote entry.

  • Can a remote application also function as a host?
    Yes — nothing in the ModuleFederationPlugin config restricts an app to only one role; a single app commonly sets both exposes (acting as a remote to whatever consumes it) and remotes (acting as a host to whatever it itself composes), which is how multi-level federation trees like shell -> section -> widget are built.
  • Does the host need the remote's source code available at build time in any form?
    No — that's the whole point. The host only needs to know the remote's federation name and the URL of its container script; the remote's actual implementation, dependencies, and source layout stay entirely inside the remote's own repository and build pipeline.
  • What is the init(shareScope) call responsible for, versus get(moduleName)?
    init registers the remote's available shared dependencies and their versions into the runtime shared scope so version negotiation can happen before any modules are actually retrieved; get is the separate, later call that actually resolves and returns the requested exposed module once negotiation has settled.

A host app is like a TV that can tune into different channels (remotes) broadcast independently by different studios; each studio builds and airs its own show on its own schedule, and the TV just needs to know the channel's frequency (URL) to tune in live, without ever needing the studio's raw footage in advance.

saying these in an interview costs you the question

  • thinks Module Federation requires a monorepo or shared build pipeline
  • believes the host needs the remote's source code at build time
  • can't distinguish host role from remote role
  • assumes an app can only be a host or a remote, never both
  • conflates Module Federation with iframes or with plain code-splitting

context

open as a page

When configuring ModuleFederationPlugin in Webpack for a remote and a host, what do the 'exposes' and 'remotes' options each declare, and how does the 'filename' option relate to the generated container file?

level: middleimportance: must knowfreq 65%

basics

~20 s

'exposes' is a remote saying 'here's what I'm sharing and its nickname'; 'remotes' is a host saying 'here's a friend's address I want to fetch code from.' 'filename' just names the small file that makes the connection work.

open as a page

In a Module Federation setup, what does marking a shared dependency like react as singleton: true with a requiredVersion do, and what happens if a host and remote have incompatible versions?

level: middleimportance: must knowfreq 60%

basics

~20 s

Shared deps are libraries (like React) that separately-built apps agree to reuse one copy of instead of each shipping their own. Marking one 'singleton' means only one copy is ever allowed to run at once; if the versions genuinely clash, the app can crash or silently duplicate the library, either way it's risky.

open as a page

What is a 'dynamic remote' in Module Federation, and how does resolving a remote's URL at runtime differ from declaring it statically in ModuleFederationPlugin's remotes config?

level: seniorimportance: should knowfreq 40%

basics

~20 s

A static remote's address is baked into the host when it's built. A dynamic remote's address is looked up while the app is actually running, for example fetched from a server, so the host doesn't need to be rebuilt just to point at a different remote.

open as a page

A host application using Module Federation goes into production, and users start seeing a blank panel where a remote-loaded micro-frontend should render, with a network error for remoteEntry.js in the console. What are the likely causes, and how should the host be built to degrade gracefully?

level: seniorimportance: should knowfreq 45%

basics

~20 s

If the piece of a page that comes from another team's app fails to load, you probably have a broken link to their code, a version clash between shared libraries, or a bug in their code. The fix is to build the page so one missing piece shows a small fallback instead of breaking the whole page.

open as a page

How does Vite's module federation approach, such as the @originjs/vite-plugin-federation or the @module-federation/vite plugin, differ mechanically from Webpack Module Federation, and in what situations would you avoid runtime module federation altogether in favor of build-time integration?

level: principalimportance: nice to knowfreq 20%

basics

~20 s

Vite-based federation tools connect apps using native browser ES modules instead of Webpack's own custom loading system, so it's lighter and faster in dev but has a shorter production track record. Sometimes the better answer is to skip runtime federation entirely and just build everything together in one monorepo.

open as a page