LogoMasst Docs

Micro-frontends Architecture

A guide to micro frontend architecture - building scalable frontend applications with independent, deployable units

What are Micro Frontends?

Micro Frontends extend the microservices philosophy to frontend development. Instead of a single monolithic frontend application, the UI is composed of smaller, independent pieces that can be developed, tested, and deployed separately.

Each micro frontend:

  • Owns a feature or page: Has clear boundaries and responsibilities.
  • Is independently deployable: Ship updates without coordinating with other teams.
  • Can use different technologies: Teams choose their own frameworks.
  • Is developed by autonomous teams: End-to-end ownership from UI to API.

Example: An e-commerce site where the Product Catalog, Shopping Cart, User Profile, and Checkout are separate micro frontends developed by different teams.


Monolith vs Micro Frontend

AspectMonolith FrontendMicro Frontends
DeploymentDeploy entire app togetherDeploy each MFE independently
Team OwnershipShared codebase, all teamsEach team owns their MFE
TechnologySingle frameworkMultiple frameworks possible
Build TimeLong (entire app rebuilt)Fast (only changed MFE)
Failure ImpactOne bug can break whole UIIsolated failures per MFE
ComplexitySimple architecture, complex codebaseComplex architecture, simpler codebases

Core Principles

1. Technology Agnostic

Each team can choose the best tools for their needs without affecting others.

Product Team     → React + TypeScript
Checkout Team    → Angular + RxJS
Marketing Team   → Vue + Nuxt
Legacy Team      → jQuery (migrating gradually)

2. Isolated Team Code

No shared state or global variables between micro frontends. Communicate through well-defined contracts.

Rule: If two MFEs need to share code, extract it to a versioned npm package.

3. Native Browser Features Over Custom APIs

Prefer browser events, URLs, and storage over custom frameworks for communication.

4. Resilient by Design

If one micro frontend fails, others should continue working.


Integration Approaches

1. Build-time Integration

Micro frontends are published as npm packages and composed during build.

{
  "dependencies": {
    "@company/catalog-mfe": "^2.1.0",
    "@company/cart-mfe": "^1.5.0",
    "@company/checkout-mfe": "^3.0.0"
  }
}
ProsCons
Simple setupRequires rebuilding host for updates
Single bundle optimizationTight coupling via versions
Works with any frameworkSlower release cycle

2. Server-side Integration

Compose micro frontends on the server using SSI (Server-Side Includes) or edge-side composition.

<!-- Main page template -->
<html>
  <body>
    <header><!--#include virtual="/mfe/header" --></header>
    <main><!--#include virtual="/mfe/product-catalog" --></main>
    <aside><!--#include virtual="/mfe/shopping-cart" --></aside>
    <footer><!--#include virtual="/mfe/footer" --></footer>
  </body>
</html>
ProsCons
Fast initial load (complete HTML)More complex server setup
SEO-friendlyLimited client-side interactivity
Independent deploymentRequires edge/CDN support

3. Client-side Integration

The browser loads and composes micro frontends dynamically.

Module Federation (Webpack 5+)

// webpack.config.js - Shell App
new ModuleFederationPlugin({
  name: 'shell',
  remotes: {
    catalog: 'catalog@https://catalog.example.com/remoteEntry.js',
    cart: 'cart@https://cart.example.com/remoteEntry.js',
  },
  shared: ['react', 'react-dom'],
});

// Usage in Shell
const CatalogPage = React.lazy(() => import('catalog/ProductList'));
ProsCons
True independent deploymentWebpack-specific (though Vite support exists)
Shared dependencies (smaller bundles)Complex configuration
Dynamic loadingRuntime errors possible

iframes

Strongest isolation but with trade-offs.

<iframe
  src="https://checkout.example.com"
  title="Checkout"
  style="border: none; width: 100%; height: 600px;"
></iframe>
ProsCons
Complete isolationPoor UX (no shared styling)
Works with any technologyPerformance overhead
Security sandboxCommunication is complex

Web Components

Framework-agnostic custom elements.

// Define in Cart MFE
class ShoppingCart extends HTMLElement {
  connectedCallback() {
    this.innerHTML = `<div class="cart">...</div>`;
  }
}
customElements.define('shopping-cart', ShoppingCart);

// Use anywhere
<shopping-cart items="3"></shopping-cart>
ProsCons
Native browser supportLimited framework integration
True encapsulation (Shadow DOM)Styling can be challenging
Works everywhereLearning curve for teams

Communication Patterns

// Cart MFE - Dispatch event
window.dispatchEvent(new CustomEvent('cart:updated', {
  detail: { itemCount: 5, total: 149.99 }
}));

// Header MFE - Listen for event
window.addEventListener('cart:updated', (event) => {
  updateCartBadge(event.detail.itemCount);
});

2. URL/Route Parameters

/products?category=electronics&sort=price

Each MFE reads its relevant params from the URL. Changes are reflected across all MFEs.

3. Shared State (Use Sparingly)

For complex scenarios, use a lightweight shared store.

// Shared event bus
const eventBus = {
  events: {},
  emit(event, data) { ... },
  on(event, callback) { ... },
  off(event, callback) { ... }
};

Best Practice: Minimize shared state. Most communication should happen through events or URL parameters.


Routing Strategies

StrategyDescriptionBest For
Route-basedEach MFE owns a route prefixPage-level micro frontends
Component-basedMultiple MFEs on same pageWidget-style composition
HybridRoute-based with component-based widgetsComplex applications

Shared Dependencies

The Problem

Multiple MFEs loading the same library (React, Lodash) wastes bandwidth and can cause conflicts.

Solutions

// Module Federation shared config
shared: {
  react: { singleton: true, requiredVersion: '^18.0.0' },
  'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
}

Styling Strategies

Preventing Style Conflicts

ApproachHow It WorksTools
CSS ModulesScoped class names per componentBuilt into Webpack/Vite
CSS-in-JSStyles generated with unique identifiersstyled-components, Emotion
Shadow DOMEncapsulated styles in Web ComponentsNative browser feature
BEM + PrefixesNaming conventions with MFE prefixManual discipline
Design SystemShared tokens, independent componentsCustom or Chakra, MUI
/* Prefixed approach */
.catalog-mfe__product-card { ... }
.cart-mfe__item-row { ... }
.checkout-mfe__form-input { ... }

Testing Strategies

Testing Pyramid for Micro Frontends

LevelWhat It TestsTools
UnitIndividual components and functionsJest, Vitest, Testing Library
ContractEvent schemas, API contractsPact, JSON Schema
IntegrationMFE composition and communicationCypress Component Testing
E2EFull user journeys across MFEsPlaywright, Cypress

Real-World Example

Streaming Platform (like Spotify/Netflix):

Team Structure:

  • Platform Team: Owns Shell, shared libraries, deployment infrastructure
  • Browse Team: Catalog browsing, recommendations
  • Player Team: Audio/video playback, queue management
  • Search Team: Search experience, filters
  • Growth Team: Onboarding, profiles, settings

When to Use Micro Frontends

✅ Good Fit

  • Large organizations with multiple frontend teams
  • Need for independent deployment cycles
  • Gradual migration from legacy systems
  • Different features require different technologies
  • Teams organized around business domains

❌ Poor Fit

  • Small teams (< 5 developers)
  • Simple applications with few features
  • No CI/CD infrastructure
  • Strong need for consistent UX (harder to maintain)
  • Performance-critical applications (added overhead)

Rule of Thumb: If a single team can manage the entire frontend, a monolith is probably better. Micro frontends solve organizational problems, not technical ones.


Summary Table

ConceptPurposeTools/Approaches
Module FederationRuntime MFE loading with shared depsWebpack 5, Vite Plugin
Web ComponentsFramework-agnostic UI componentsNative Custom Elements
single-spaFramework for composing MFEssingle-spa, qiankun
Custom EventsMFE-to-MFE communicationBrowser CustomEvent API
Design SystemConsistent UI across MFEsStorybook, shared component lib
Contract TestingEnsure MFE compatibilityPact, JSON Schema

Interview Tips

  • Explain the "why": Micro frontends solve team scalability, not technical complexity.
  • Discuss trade-offs: More infrastructure complexity, potential UX inconsistency, performance overhead.
  • Compare approaches: Know when to use Module Federation vs iframes vs Web Components.
  • Cover communication: Explain event-based patterns and why to avoid shared state.
  • Mention real examples: IKEA, Spotify, DAZN, and Zalando use micro frontends.
  • Connect to microservices: They're the frontend equivalent—same principles of independence and ownership.
  • Address performance: Discuss shared dependencies, lazy loading, and caching strategies.

Micro Frontends enable large organizations to scale frontend development by giving teams autonomy over their features. Success requires strong DevOps practices, clear team boundaries, and careful attention to UX consistency.