Skip to main content
Micro Frontends: When and How to Split Your UI

Micro Frontends: When and How to Split Your UI

Sep 28, 2025

Your frontend monolith is getting too big. Deployments take forever. Teams step on each other. Every change risks breaking something unrelated.

Micro frontends promise to fix this by letting teams own and deploy pieces independently. But like microservices, theyre not free. Lets figure out when they make sense.

What Are Micro Frontends?

Instead of one big app, you have multiple smaller apps that compose into one:

Each micro frontend:

  • Has its own repo and CI/CD
  • Can use different frameworks (but probably shouldnt)
  • Deploys independently
  • Owned by one team

Integration Approaches

1. Build-Time Integration (Module Federation)

Webpack 5 Module Federation is the modern way:

// products-mfe/webpack.config.js
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'products',
      filename: 'remoteEntry.js',
      exposes: {
        './ProductList': './src/ProductList',
        './ProductDetail': './src/ProductDetail',
      },
      shared: ['react', 'react-dom'],
    }),
  ],
};

// shell-app/webpack.config.js
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'shell',
      remotes: {
        products: 'products@https://products.example.com/remoteEntry.js',
        cart: 'cart@https://cart.example.com/remoteEntry.js',
      },
      shared: ['react', 'react-dom'],
    }),
  ],
};
// Shell app loads remote components
const ProductList = React.lazy(() => import('products/ProductList'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <ProductList />
    </Suspense>
  );
}

2. Runtime Integration (iframes)

Old school but still works:

Pros: Complete isolation, any framework Cons: Performance, communication is awkward, styling issues

3. Web Components

Framework-agnostic custom elements:

// products-mfe/product-card.ts
class ProductCard extends HTMLElement {
  connectedCallback() {
    const productId = this.getAttribute('product-id');
    this.innerHTML = `<div class="product">...</div>`;
  }
}

customElements.define('product-card', ProductCard);

// Shell app
<product-card product-id="123"></product-card>

Communication Between MFEs

// Shared event bus
const eventBus = {
  events: new Map<string, Function[]>(),

  subscribe(event: string, callback: Function) {
    if (!this.events.has(event)) {
      this.events.set(event, []);
    }
    this.events.get(event).push(callback);
  },

  publish(event: string, data: any) {
    const callbacks = this.events.get(event) || [];
    callbacks.forEach(cb => cb(data));
  }
};

// Cart MFE
eventBus.publish('cart:updated', { itemCount: 3 });

// Header MFE
eventBus.subscribe('cart:updated', ({ itemCount }) => {
  updateBadge(itemCount);
});

When Micro Frontends Make Sense

Good fit:

  • Multiple teams working on same product
  • Teams need to deploy independently
  • Different parts evolve at different speeds
  • You have the infrastructure maturity

Bad fit:

  • Small team (under 10 devs)
  • Simple application
  • Tight deadlines (adds upfront complexity)
  • No DevOps support

The Gotchas

1. Shared Dependencies

Multiple copies of React = bloated bundle:

// Without sharing: React loaded 4 times = 400KB
// With Module Federation sharing:
shared: {
  react: { singleton: true, requiredVersion: '^18.0.0' },
  'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
}

2. Styling Conflicts

CSS leaks between MFEs:

/* Products MFE */
.button { background: blue; }

/* Cart MFE */
.button { background: green; }

/* Chaos! */

Solutions:

  • CSS Modules
  • CSS-in-JS with unique prefixes
  • Shadow DOM

3. Consistent UX

Each team builds slightly different buttons, modals, etc.

Solution: Shared design system as a package:

// @company/design-system
import { Button, Modal, Card } from '@company/design-system';

Simpler Alternatives

Before going full micro frontend:

  1. Monorepo with good boundaries - Nx, Turborepo
  2. Feature flags - Deploy together, release separately
  3. Plugin architecture - Load features dynamically

Quick Checklist

Before adopting micro frontends:

  • [ ] 3+ teams working on frontend
  • [ ] Clear domain boundaries
  • [ ] Teams have DevOps capabilities
  • [ ] Design system exists (or planned)
  • [ ] Accepted the complexity tradeoff

Further Reading

Micro frontends solve real problems for large organizations. But they add significant complexity. Make sure you actually have the problems they solve before adopting them.

© 2026 Tawan. All rights reserved.