skip to content

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