skip to content

Microfrontends

Splitting a frontend into independently deployable pieces owned by different teams. You will cover how the pieces are composed, how they share dependencies, who owns which route, and the contracts that keep them from breaking each other.

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

questions

page 1 of 2

In a microfrontend architecture, what is the basic difference between mounting a microfrontend as a JavaScript bundle directly into the DOM versus embedding it via an iframe?

level: juniorimportance: must knowfreq 65%

answer

  1. same DOM vs separate document
  2. postMessage handshake
  3. shared framework instance via module federation
  4. blast-radius containment
  5. iframe SEO weakness

basics

~20 s

JS mount loads the microfrontend's code into the same page so it shares the DOM and can talk to other parts easily. An iframe loads it as a separate mini-webpage inside a box, fully isolated but harder to communicate with.

solid answer

~30 s

JS-bundle mounting (e.g., via single-spa or Module Federation) loads each microfrontend's JS into the host page's own DOM/JS realm, giving shared routing, shared dependencies, and cheap in-memory communication (custom events, shared state), but risking CSS/JS collisions and requiring careful dependency management. Iframe embedding gives full isolation — separate DOM, CSS, JS globals, even separate origin — so a broken or malicious microfrontend can't touch the host, at the cost of duplicated framework payloads, awkward cross-frame messaging (postMessage), inconsistent viewport/scroll behavior, and worse accessibility/SEO.

go deeper

for a junior

Should describe the surface difference — one shares the page, one is a sandboxed sub-page — and give one reason to pick each (seamless UX vs isolation).

for a middle

Should name concrete mechanisms (custom events/shared bus for JS mount, postMessage for iframe) and at least one concrete cost of each (CSS/global collisions vs duplicated framework payload).

for a senior

Should reason about version-skew coordination costs in JS mounting (shared-dependency resolution) and layout/accessibility friction in iframes, and pick the right tool given a stated isolation requirement.

for a principal

Should connect the choice to org-level concerns — team autonomy vs blast-radius containment, security boundary requirements for third-party embeds, and how the decision constrains future composition options.

## What composition means Microfrontend composition is the mechanism by which independently built and deployed frontend pieces are assembled into one coherent page or application for the end user. Two of the most common **client-side composition primitives** are direct JavaScript mounting and iframe embedding, and the choice between them sits at the center of nearly every microfrontend trade-off discussion. ## The two primitives side by side | Property | JavaScript-bundle mounting | Iframe embedding | |---|---|---| | Browsing context | the same context as the shell | a separate context, with its own DOM and CSS cascade | | Communication | custom DOM events, a shared pub/sub bus, imported utility functions | `postMessage`, asynchronous and string-serializable | | Framework runtime | shared instances via module federation | its own copy per iframe | | Isolation | developer discipline and naming conventions | enforced by the browser itself | | Deep-linking, back-button behavior, and accessibility | automatic with same-document JS mounting | deliberate extra work | | SEO | — | weaker by default | ## How JavaScript-bundle mounting works With **JavaScript-bundle mounting**, each microfrontend ships as a set of JS/CSS assets that the host application (or an orchestrator library such as `single-spa`, or a bundler-level mechanism like Webpack/Rollup Module Federation) fetches and executes inside the same browsing context as the shell. Concretely: 1. The host page loads a root HTML document. 2. It dynamically imports each microfrontend's JS bundle. 3. It calls a lifecycle hook (`mount/bootstrap/unmount`). 4. The microfrontend renders its markup into a designated DOM node that already lives on the page. Because everything executes in one JS realm and one DOM tree, microfrontends can share a router, a design-token CSS layer, even framework runtime instances (React, Vue) via module federation's shared-scope mechanism, and they can communicate cheaply: - custom DOM events - a shared pub/sub bus - directly imported utility functions This tight coupling is exactly why it's popular for cohesive product experiences: navigating from a search microfrontend to a cart microfrontend feels instant because there's no full page reload and no cross-boundary handshake. ## The cost of that cohesion The cost of that cohesion is the **absence of a hard isolation boundary**. - Every microfrontend's CSS can leak into every other's (mitigated but not eliminated by CSS Modules, Shadow DOM, or naming conventions like BEM). - Every microfrontend's JavaScript runs with the same global `window` object, so one team's global assignment can silently collide with another's. - A memory leak or infinite loop in one microfrontend can degrade or crash the whole page. - **Version skew** is also a live problem: if two microfrontends need incompatible major versions of the same shared dependency, module federation's shared-scope resolution has to pick one (or duplicate the dependency, defeating the point), which becomes a genuine coordination cost between teams that are supposed to be independent. ## What the iframe boundary buys Iframe-based composition takes the opposite trade-off. Each microfrontend is served as its own standalone HTML document loaded into an `iframe` element on the host page. Because an iframe is a **separate browsing context**, it gets: - its own DOM - its own CSS cascade - its own JavaScript global scope - and — if served from a different origin — its own same-origin-policy sandbox enforced by the browser itself, not by developer discipline This is the strongest isolation guarantee available in a browser: a runaway script, a CSS reset, or even a security exploit inside the iframe cannot reach into the host page or sibling iframes unless the host explicitly opens a channel. That's why iframes remain the tool of choice when isolation is a hard requirement — embedding a genuinely untrusted third-party widget (an ad, a payment form from a different vendor, a partner's embedded dashboard) is a textbook iframe use case. ## What the iframe boundary costs The costs show up in user experience and engineering ergonomics. - **Communication** across the iframe boundary requires `postMessage`, an asynchronous, string-serializable API that both sides must agree on — there's no calling a function or sharing an object reference across the boundary. - Each iframe typically **re-downloads and re-instantiates** its own copy of any shared framework runtime, so if five microfrontends on a page each iframe-embed their own React, the user pays for five React downloads and five separate render trees, hurting Time-to-Interactive and memory footprint. - **Layout** is awkward: an iframe has a box with its own scrollbar by default, so making content flow naturally with the rest of the page (variable height, shared scrolling, focus management, printing) needs extra plumbing such as resize-observer-based height syncing. - Deep-linking, back-button behavior, and **accessibility** (focus can get trapped at an iframe boundary) all need deliberate extra work that's automatic with same-document JS mounting. - **SEO** is also weaker by default, since search crawlers historically render iframe content inconsistently or attribute it separately from the parent document. ## Which one to reach for In practice, teams pick JS-bundle mounting when the microfrontends are first-party, trusted, and need to feel like one seamless product. They reach for iframes specifically when isolation trumps cohesion: - embedding a third party - isolating a legacy app that can't be safely refactored to share a DOM - building an internal tool catalog where blast-radius containment matters more than a seamless UX Recognizing which failure mode you're optimizing against — a bug in one team's code breaking everyone's page versus a page that feels like several different websites stitched together — is usually the deciding question in an interview setting.

  • How does Webpack/Module Federation try to avoid duplicate framework downloads that plain iframe composition suffers from?
    Module Federation lets microfrontends declare shared dependencies (like React) in a shared scope with semver ranges; at runtime the host resolves a single compatible instance and only downloads it once, injecting it into every consuming microfrontend instead of each bundling its own copy. If versions are incompatible it falls back to loading both, which reintroduces duplication, so teams still need to coordinate major-version bumps of shared libraries.
  • If you must use iframes but want the microfrontend to blend into the page layout with auto height and no visible scrollbar, how would you achieve that?
    The iframe's own document posts its content height to the parent via postMessage (or the parent uses a ResizeObserver on a proxy element), and the parent then sets the iframe element's height to match, disabling the iframe's internal scrollbar with CSS overflow:hidden. This has to be re-triggered on content changes, which adds ongoing plumbing the JS-mount approach doesn't need.
  • What's a scenario where JS-bundle mounting's shared-global-scope risk actually causes a production incident?
    Two teams both attach a convenience library to a shared global variable on window; when both microfrontends load on the same page, the second one silently overwrites the first's version, producing subtle bugs only visible when both are present together — a class of bug that passes each team's isolated tests but fails in the combined page, exactly what hard iframe isolation would have prevented.

JS mounting is like several chefs cooking in the same open kitchen sharing pots and heat — fast handoffs but a spill affects everyone; an iframe is like each chef working in a sealed kitchen booth passing only notes under the door — safe but slower and with duplicated equipment.

saying these in an interview costs you the question

  • Says iframes and JS mounting are basically interchangeable performance-wise
  • Doesn't mention that JS mounting shares one JS global/window
  • Thinks iframes automatically share cookies/session with the parent regardless of origin
  • Can't name postMessage as the iframe communication mechanism
  • Assumes duplicate framework downloads only happen with iframes, never with JS mounting

context

open as a page

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%

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.

open as a page

In a microfrontend shell application, what is the difference between path-based routing (e.g. example.com/checkout) and hash-based routing (e.g. example.com/#/checkout) for deciding which microfrontend to load?

level: juniorimportance: must knowfreq 70%

basics

~20 s

Path-based routing uses the real URL path and needs server/CDN config to serve the app for every path; hash-based routing puts the route after a # so the browser never asks the server for it, but it looks less clean and hurts SEO.

open as a page

In a microfrontends architecture, what is the core difference between integrating a microfrontend at build time versus at runtime?

level: juniorimportance: must knowfreq 70%

basics

~20 s

Build-time means you bake all the pieces together into one app before you ship it, like baking ingredients into one cake. Runtime means the browser loads separate pieces live, like assembling a meal from dishes served at the table.

open as a page

In a microfrontend architecture where several independently-built apps are combined on one page, what is the difference between sharing a UI library like React as a 'singleton' versus letting each microfrontend bundle its own 'scoped' copy, and why does the choice matter?

level: juniorimportance: must knowfreq 65%

basics

~20 s

Singleton means every microfrontend uses one shared copy of a library loaded once on the page. Scoped means each microfrontend ships and uses its own private copy. Singleton saves download size but couples apps; scoped isolates apps but repeats code.

open as a page

In a microfrontend architecture, a 'shell' application loads several independently built and deployed fragments (e.g. a header team's app, a checkout team's app) at runtime. What is a 'stable integration contract' between these teams, and why do they need one instead of just having each fragment reach into the others' code or DOM directly?

level: juniorimportance: must knowfreq 55%

basics

~20 s

A contract is the agreed set of inputs (props), outputs (events), and shared visual rules (design tokens) two teams promise not to change without warning, so each team can update its own code without breaking the others.

open as a page

In server-side composition of microfrontends, such as using Server-Side Includes (SSI) or an edge-layer composition service, what actually happens between the browser's request and the fully assembled HTML response, and why does this approach tend to help SEO more than pure client-side JS mounting?

level: middleimportance: must knowfreq 70%

basics

~20 s

The server (or a CDN edge) fetches each microfrontend's HTML piece and stitches them into one page before sending it to the browser, so the browser gets a complete, already-composed page instead of empty boxes that JavaScript fills in later.

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

In a microfrontend shell, how does clicking a link inside one microfrontend (e.g. a 'View Order' link inside a Cart microfrontend that should open a route owned by a separate Orders microfrontend) trigger a client-side navigation instead of a full page reload?

level: middleimportance: must knowfreq 65%

basics

~20 s

The link isn't a normal <a> that reloads the page; the shell's router intercepts the click, updates the browser URL with the History API, notices the new path belongs to a different microfrontend, unmounts the old one, and mounts the new one — all without asking the server for a new page.

open as a page

With build-time integration — say a microfrontend is imported as an npm package inside a monorepo — walk through what has to happen for one team's UI change to reach production, and what that implies for release cadence across teams.

level: middleimportance: must knowfreq 75%

basics

~10 s

The team's code gets pulled into the main app during its build, so nothing goes live until the whole app is rebuilt and redeployed together — teams can't ship on their own schedule.

open as a page

In a runtime-integrated microfrontend system using Webpack Module Federation, concretely describe what happens in the browser from the moment a host page loads to the moment a remote microfrontend's UI is rendered.

level: middleimportance: must knowfreq 65%

basics

~20 s

The host page loads a small manifest file from the microfrontend's server that tells the browser where to fetch its actual code, then the browser downloads and runs that code on the spot and slots it into the page.

open as a page

When a host application and several remote microfrontends each declare a required version range for a shared library (for example one remote needs '^17.0.0' and another needs '^18.2.0'), how does a module-federation-style runtime decide which actual version gets loaded on the page, and what options does it give you to control that decision?

level: middleimportance: must knowfreq 60%

basics

~20 s

The runtime looks at every version range each app asked for, tries to find one already-loaded version that satisfies all of them, and uses that. If none satisfies everyone, or if you set stricter rules, it either loads a second separate copy for the mismatched app or throws an error, depending on your configuration.

open as a page

Several teams each run their own CI/CD pipeline and deploy their microfrontend to production independently of the others, with no shared release train. What must the integration contract guarantee for that independence to be safe, and what specifically goes wrong if a team violates it mid-deploy?

level: middleimportance: must knowfreq 60%

basics

~20 s

Every deploy must keep working with old and new versions of everyone else at the same time, because you never know exactly who's running what. If a team ships a change that only works with a version nobody else has deployed yet, things break for real users mid-rollout.

open as a page

A team wants both strong SEO for a product page and rich, app-like interactivity for a checkout flow within the same page. Why might they choose a hybrid composition strategy — server or edge composition for some sections and client-side JS mounting for others — instead of picking one approach uniformly, and what new complexity does mixing them introduce?

level: seniorimportance: must knowfreq 55%

basics

~20 s

They use the server-composed approach for parts search engines need to read, like product details, and the client-mounted approach for parts that need heavy interactivity, like an add-to-cart form, because no single method is best at both. The cost is now managing two different composition systems and keeping them in sync on one page.

open as a page

Compare what a rollback actually looks like — what gets reverted, how fast, and what the blast radius is — for a bug shipped via build-time microfrontend integration versus one shipped via runtime integration, such as a Module Federation remote.

level: seniorimportance: must knowfreq 60%

basics

~20 s

With build-time integration, undoing a bug means redeploying the whole combined app to an older version, which affects everyone at once. With runtime integration, the team that broke it can usually just redeploy their own piece, so the fix or rollback is smaller and faster.

open as a page

In production, what concrete symptoms show up when a library that was supposed to be a singleton across microfrontends ends up loaded twice on the same page, and how would you diagnose that it's a duplicate-instance problem rather than an application bug?

level: seniorimportance: must knowfreq 55%

basics

~20 s

You'll see weird bugs like broken shared state, theme/context not applying somewhere, or a hooks crash -- but only for one part of the page, not everywhere. Checking the browser's network tab shows the same library file downloaded twice, which confirms two separate copies are running.

open as a page

How does Conway's Law — the observation that a system's architecture mirrors the communication structure of the organization that built it — inform how you draw the boundaries between microfrontends and assign team ownership, and what goes wrong when the technical boundaries and the team boundaries don't match?

level: seniorimportance: must knowfreq 50%

basics

~20 s

Draw the lines between microfrontends the same way you'd draw the lines between teams — one team, one clear piece of the product. If a boundary forces two teams to constantly touch the same fragment, you'll get either confusing shared code or constant coordination meetings.

open as a page

At an organization with 40+ teams each owning microfrontends registered into a shared shell's route table, what technical and process mechanisms prevent route ownership from silently drifting out of sync with the route table as teams reorganize, rename services, or split ownership of a URL prefix?

level: principalimportance: must knowfreq 35%

basics

~20 s

You need something better than tribal knowledge — a checked-in, machine-readable registry of who owns which URL, automated checks that stop two teams from claiming the same route by accident, and a real process for handing off or splitting ownership when teams reorganize.

open as a page

When a platform team defines a route table like `/checkout/* -> checkout-team`, `/search/* -> search-team`, `/account/* -> account-team` for a microfrontend shell, what problem does this mapping solve, and what happens when two teams need to render content on the same URL segment (e.g. a global site-wide header that appears on every path)?

level: middleimportance: should knowfreq 55%

basics

~20 s

The mapping tells the shell which team's code to load for a given URL, so each team can build and deploy independently. Shared elements like a global header that appear on every page are usually owned by a separate, always-mounted piece rather than by any single route-owning team.

open as a page

A team that owns a checkout microfrontend wants to add a required new field to the payload of an event it emits (an event other teams' fragments already listen for). What does a safe versioning policy for rolling out this kind of change look like, from proposal to old-version retirement?

level: middleimportance: should knowfreq 45%

basics

~20 s

Don't flip the switch all at once. Send both the old and new versions of the data for a while, tell other teams the old one is going away on a date, watch to see who's still using it, and only remove the old version once nobody is.

open as a page

When microfrontends are composed on the client using native Web Components (custom elements with Shadow DOM) as the integration contract, what isolation does Shadow DOM actually provide, and what does it NOT protect against compared to a full cross-origin iframe boundary?

level: seniorimportance: should knowfreq 45%

basics

~20 s

Shadow DOM keeps each microfrontend's CSS and internal markup from leaking into or being affected by the rest of the page, like a bubble around its styles and structure. But it does not stop its JavaScript from touching the same page-wide window object, unlike an iframe which blocks that too.

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

A shell app mounts a microfrontend that has its own internal React Router instance for sub-navigation (e.g. tabs within `/account/*`). What specifically needs to be synchronized between the shell's top-level router and the microfrontend's internal router so that browser back/forward and deep-linking both work correctly?

level: seniorimportance: should knowfreq 50%

basics

~20 s

The microfrontend's internal router must not fight the shell's top-level router over control of the browser's URL and back button — usually the MFE's router is scoped to only the part of the path under its own prefix, and both must agree on one shared history stack instead of each keeping a separate idea of 'where we are.'

open as a page

Some microfrontend platforms deliberately use full page reloads (a real HTTP navigation) between top-level sections instead of client-side routing with a shared shell router — e.g. navigating from a marketing site's `/blog/*` to its `/app/*` product experience. When is that the right trade-off instead of building a single client-side-routed shell across all sections?

level: seniorimportance: should knowfreq 40%

basics

~20 s

If two sections are built with totally different tech, teams, or release cycles, and users rarely bounce between them quickly, it's often simpler and safer to just let the browser do a normal page load between them instead of forcing them into one shared client-side router.

open as a page

In a runtime-integrated microfrontend setup where the host loads a remote's JavaScript bundle by a fixed URL, such as a stable remoteEntry.js path, what cache-invalidation problem can arise, and what are the common strategies to avoid serving stale code?

level: seniorimportance: should knowfreq 55%

basics

~20 s

If the browser or a CDN caches the old file at that same web address, users can keep getting yesterday's broken code even after the team ships a fix, because nothing tells the cache the file changed.

open as a page

What is an import map, and how do import-map overrides let a team swap which build of a shared dependency loads for a specific microfrontend or environment without rebuilding and redeploying every app on the page?

level: seniorimportance: should knowfreq 35%

basics

~20 s

An import map is a config that tells 'import react' to actually fetch a specific URL. Overriding one entry lets you redirect just that library to a different file -- like a staging build or hotfix -- without touching or rebuilding any of the apps that import it.

open as a page

A platform introduces consumer-driven contract testing between microfrontend producer teams and the teams that consume their props/events, running these tests in each producer's CI before deploy. How does this actually work in a microfrontend context, and what class of breaking change does it fail to catch?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Each team that depends on another team's fragment writes down exactly what they expect from it, and the producing team runs those written expectations as automated checks before every deploy — so a breaking change gets caught in CI instead of in production. It can't catch a new team you didn't know was depending on you.

open as a page

You're advising an organization that wants to adopt runtime-integrated microfrontends, for example via Module Federation, specifically to let teams deploy independently. Under what conditions would you recommend against it, even though independent deployability sounds strictly better?

level: principalimportance: should knowfreq 45%

basics

~20 s

If the teams don't actually need to ship on different schedules, or the org can't yet handle the extra operational work like version conflicts and monitoring many moving pieces, the simpler build-time setup is usually the better choice.

open as a page

showing 1–30 of 34