skip to content

Composition Strategies

Where the pieces get assembled: on the server or edge, in the browser via iframes, web components or JS mounts, or a hybrid. Each option lands somewhere different on isolation, latency and SEO, which is exactly what an interviewer wants you to weigh.

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

questions

5

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 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

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

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

Some organizations move page composition from an origin application server to the CDN edge, using platforms like Cloudflare Workers or Fastly Compute, instead of a traditional origin-based composition service. What does moving composition to the edge actually change about latency and failure behavior, and what new constraints does the edge runtime environment impose that don't exist on an origin server?

level: principalimportance: nice to knowfreq 25%

basics

~20 s

Doing the page assembly on servers physically closer to the visitor, at the CDN edge, instead of far away at a central data center, cuts the network travel time, so pages come together faster. But those edge servers are much more limited in memory, CPU time, and what code they can run than a normal origin server.

open as a page